这两个用于调用事件的代码示例有什么区别?
样本1
public void OnDataChanged()
{
if (DataChanged != null)
{
DataChanged(this);
}
}
样本2
DataChanged.Invoke(this);
我应该何时使用每种方法来调用自定义事件?为什么有时候我尝试使用DataChanged.Invoke(this)
调用事件时会得到NullReferenceException,但是当我将事件调用转换为示例1中的方法时,DataChanged
永远不会变为null?
答案 0 :(得分:15)
OnXYZ
方法应始终遵循以下格式:
public void OnXYZ()
{
var evt = XYZ;
if (evt != null)
evt(sender, e); // where to get e from differs
}
这种形式有几个原因:
if evt != null
检查可确保我们不会尝试调用null
代理人。如果没有人将事件处理程序连接到事件,就会发生这种情况。evt
,我们可以在检查非null后安全地调用它,因为没有人可以改变它在if
之后但在通话之前。 e
传递的内容有所不同,如果您需要使用参数传递EventArgs
后代,则有两种方法:
public void OnXYZ(string p)
{
var evt = XYZ;
if (evt != null)
evt(sender, new SomeEventArgs(p));
}
或更常见的是:
public void OnXYZ(SomeEventArgs e)
{
var evt = XYZ;
if (evt != null)
evt(sender, e);
}
此语法:
evt(sender, e);
只是另一种写作方式:
evt.Invoke(sender, e);
另请注意,在您的课程外部,该活动是一个活动,您只能add
或remove
个活动处理程序。
您的类的内部,事件是委托,您可以调用它,检查目标或方法,遍历订阅者列表等。
此外,在C#6中引入了一个新的运算符?.
- Null-conditional operator - 这基本上是if not-null, dereference
的缩写,可以缩短此方法:
public void OnXYZ(SomeEventArgs e)
{
var evt = XYZ;
if (evt != null)
evt(sender, e);
}
进入这个:
public void OnXYZ(SomeEventArgs e)
{
XYZ?.Invoke(sender, e);
}
可以通过使用表达身体的成员进一步缩短:
public void OnXYZ(SomeEventArgs e) => XYZ?.Invoke(sender, e);
请注意,无法写下:
XYZ?.(sender, e);
所以在这种情况下你必须自己使用Invoke
。
答案 1 :(得分:2)
当我将事件调用转换为示例1中的方法时,DataChanged永远不会变为空
然后你只是看两种不同的场景。
如果您未声明 System.out.println(TimeZone.getTimeZone("Australia/Sydney").inDaylightTime(new Date()));
System.out.println(TimeZone.getTimeZone("Europe/Moscow").inDaylightTime(new Date()));
之类的事件,则public event EventHandler YourEvent = delegate { };
为YourEvent
,直到某个消费者订阅它为止。
答案 2 :(得分:1)
如果没有订阅DataChanged它将被设置为null,所以当你尝试执行DataChanged.Invoke(this)时,你会得到一个NullRefException,因为它真的试图做null.Invoke (这个)。附加if(DataChanged!= null)的原因是为了避免在没有人订阅该事件时发生这种情况。
我不相信当你使用Sample 1 DataChanged永远不会为null时,它永远不会到达.Invoke来抛出异常。如果没人订阅,它将始终为null。
答案 3 :(得分:1)
您确定,在示例1中,DataChanged
永远不会为空吗?或者你只是没有得到NullReference异常(因为你在DataChanged
语句中检查if
是否为空)?
让我们从基础开始。活动是一种特殊的代表。当你调用DataChanged(this)和DataChanged.Invoke(this)时,它是一回事。为什么?因为它编译成同样的东西。总而言之,DataChanged(this)
只是调用DataChanged.Invoke(this)
的简写。
现在,为什么我们需要检查空引用(如示例1中所示)。
基本上,当您调用事件时,您将调用订阅此事件的所有方法(例如DataChanged += someEventHandler
)。
如果没有人订阅此活动,则其值为null
。没有分配方法来处理此事件。换句话说:事件处理程序为空。
这就是为什么在调用事件之前检查null是一个好习惯。
答案 4 :(得分:0)
一个例子:
public void OnAbc(){
var data=Abc;
if(!String.IsNullOrEmpty(data))
Abc(sender,e);
}