Man*_*and 7 c# null events event-handling
通常可以在这里找到这样的问题的答案,或者如果不是在这里,可以在MSDN上找到,但我看了看,但没有找到答案.实验似乎表明代码如下:
SomeControl.Click += null;
Run Code Online (Sandbox Code Playgroud)
没有害处.或者至少触发事件并不会通过尝试调用null事件侦听器来抛出异常(我可以告诉).然而,似乎无处将验证我希望,这样的代码是不是做至少在网络上的东西,我可能不想做.例如,导致Click事件认为它有听众,当它可能没有时,并且在"现在让我们执行空检查并调用所有非空的侦听器"代码中浪费那些非常珍贵的超超微秒.
似乎文档应该说明如果RHS上的监听器为空,+ =和 - =运算符的行为是什么.但就像我说的那样,我无法在任何地方找到该文档.我相信这里有人可以提供它,但....
(显然,我的代码没有硬编码的null;我的问题更多的是关于这样的代码是浪费还是完全无害:
public static void AddHandlers([NotNull] this Button button,
[CanBeNull] EventHandler click = null,
[CanBeNull] EventHandler load = null)
{
button.Click += click;
button.Load += load;
}
Run Code Online (Sandbox Code Playgroud)
或者如果我[ 因为任何原因需要 ]在每个这样的+ =操作周围添加空检查.)
考虑以下代码:
void Main()
{
var foo = new Foo();
foo.Blah += Qaz;
foo.Blah += null;
foo.OnBlah();
}
public void Qaz()
{
Console.WriteLine("Qaz");
}
public class Foo
{
public event Action Blah;
public void OnBlah()
{
var b = Blah;
if (b != null)
{
Console.WriteLine("Calling Blah");
b();
Console.WriteLine("Called Blah");
}
}
}
Run Code Online (Sandbox Code Playgroud)
因为它运行没有错误并产生以下输出:
Calling Blah
Qaz
Called Blah
Run Code Online (Sandbox Code Playgroud)
如果我删除该行,foo.Blah += Qaz;那么代码运行没有错误,但不产生输出,因此null有效地忽略了处理程序.
就IL而言,该行foo.Blah += null;产生以下IL:
IL_001A: ldloc.0 // foo
IL_001B: ldnull
IL_001C: callvirt Foo.add_Blah
IL_0021: nop
Run Code Online (Sandbox Code Playgroud)
所以,它表现得像nop,但它清楚地运行代码.
答案取决于+=(or -=) 运算符是应用于事件还是委托。
在您的AddHandlers示例中,Button该类可能将Click和定义Load为事件,而不是委托。当它的左操作数是一个事件时,+=运算符只需调用add事件的访问器,而无需任何额外的空检查。也就是说,在幕后button.Click += value;只是一个方法调用:
button.add_Click(value);
Run Code Online (Sandbox Code Playgroud)
与任何其他方法一样,如何add_Click处理空参数完全取决于Button类。
现在考虑Button该类如何实际实现该Click事件。这是一种方法:
private EventHandler _click;
public event EventHandler Click
{
add { _click += value; }
remove { _click -= value; }
}
// Or even shorter...
// public event EventHandler Click;
// ... which is the same as above plus extra stuff for thread safety.
Run Code Online (Sandbox Code Playgroud)
在这个实现中,EventHandler是一个委托类型。当两个操作数都是委托时,+=运算符调用Delegate.Combine. 文档说Delegate.Combine(a, b)返回:
具有调用列表的新委托,该调用列表按该顺序连接a和b的调用列表。返回一个,如果b为空,返回b,如果一个是空引用,并返回如果两个空引用一个和b是空引用。
结论:只要Button该类以“标准”方式实现其事件(而不是,例如,以显式方式跟踪侦听器List<EventHandler>),则button.Click += null;最终不会添加空侦听器。
| 归档时间: |
|
| 查看次数: |
730 次 |
| 最近记录: |