2009-03-04 120 views
4

所以我坚持固定/维护另一个程序员代码(BLECH)设置/删除事件处理程序的.Net

我的规则坚定的教授,“如果没坏不要修复它!”所以depsite每次遇到可怕的代码时都想改变一些东西,我只限于改变绝对最小数量的代码来完成所需的修复。但是在某些情况下,我需要了解一些内容,然后再试着去改变它。

我碰到这一点在这里:

region.LineSelected = (x) => { }; 

,我想知道,如果它是与此相同:

region.LineSelected = null; 

我想是100%肯定的什么样的第一行是做在我改变它的方法之前。

回答

8

根据我目前对这个主题的看法编辑

他们不一样。 lambda版本将一个事件处理程序添加到一个空的匿名方法中。这允许其他代码自由引发LineSelected()而不用担心它是否为空(即没有侦听器)。

例如,

var lineSelected = this.LineSelected; 

if (lineSelected != null) 
{ 
    lineSelected(EventArgs.Empty); 
} 

如果事情引发该事件的如果但在此之前后在另一个线程从LineSelected退订上面的语句可以抛出一个NullReferenceException。 将LineSelected分配给一个临时变量,然后引发可以调用未订阅的事件侦听器。 将事件处理程序分配给局部变量是处理空委托的推荐方法。

通过添加一个空的委托,其他代码总是能够调用LineSelected而不用担心NullReferenceException。 通过将多播事件委托分配给本地变量,可以确保该值不能被另一个线程修改。

+0

你能解释一点吗? – 2009-03-04 17:02:27

+0

好的,感谢编辑,我现在明白了。 – 2009-03-04 17:06:22

+0

很高兴有帮助。 – 2009-03-04 17:06:50

1

不,它不是一回事 - 第一行将LineSelected指定为与null完全不同的空代表。

发现差异的最简单方法是查看编译器在使用lambda语法时为其生成的代码。此代码:

using System; 

class Program 
{ 
    static void Main() 
    { 
     Action<int> func0 = (x) => { }; 
     Action<int> func1 = null; 
    } 
} 

真编译成这样:

internal class Program 
{ 
    // Methods 
    private static void Main() 
    { 
     Action<int> func0 = delegate (int x) { 
     }; 
    } 
} 

注意,编译器很聪明,因为它被设置为null,而不是其他地方引用删除func1。但请注意func0仍然存在,并且设置为代表,尽管与null完全不同但与此不同。

2

我想不出任何理由有第一行代码。我唯一能想到的是在引发LineSelected事件时,如果在类中有第一行代码,则不需要检查LineSelected事件是否为空。即:

if (this.LineSelected != null) 
{ 
    LineSelected(this,new EventArgs()); 
} 

相反,你可以引发没有空检查的事件。

但是,对于第二行代码,您需要检查是否有空值。

1

它们不一样,因为事件处理程序已设置。

可以说是公开LineSelected类,忘了:

if(LineSelected != null) 
    LineSelected(...) 

如果该类被调用LineSelected,没有人听,那么它会抛出NullReferenceException异常

注意,你可以也可以这样做(在区域内)以避免竞争条件:

var event = LineSelected; 如果(事件!= NULL) 事件(...

1

我认为这是一个技术,避免每次事件null检查。

如果LineSelected事件提高代码没有一个适当的空检查,那么这将导致异常:

region.LineSelected = null; 

/* no event handlers added to LineSelected */ 

class Region { 
    void OnLineSelected() { 
     // Null error! 
     LineSelected(); 
    } 
} 

但是,如果有一个空的无副作用的处理程序添加到它,那么上面的代码将工作得很好,即使没有人处理程序添加到该事件,因为总会有那个空的处理器连接。

1

要展开什么理查德和安德鲁说,它是

region.LineSelected = delegate {}; 

相当于这意味着当你提高的情况下,你并不需要先检查空,因为它有一个代表(在小的性能价格击中)

2

这不是一个事件处理程序,这是一个简单的代理。 (必须用+ =和 - =来修改事件处理程序以附加和分离事件)。

如前所述,将委托属性设置为空处理程序意味着在调用委托之前不必执行空检查(假设没有其他设置可以将其设置为空)。

这可能会使调用代码更方便,但它不应该被混淆为性能改进(通过消除检查null的需要)。通常,委托方法调用的开销将显着高于空检查的开销。可能会有一些场景(例如,如果委托人有99.99%的时间是“真正的”实现),避免使用空值检查可以提高性能,但很难想象这种情况下,那里的性能差异可能足以影响值得一提的是,这也不能保证完全取消委托调用,而是为了提高效率。