C# 为什么在调用自定义事件之前要检查null?
调用事件的这两个代码示例之间有什么区别 样本1C# 为什么在调用自定义事件之前要检查null?,c#,events,C#,Events,调用事件的这两个代码示例之间有什么区别 样本1 public void OnDataChanged() { if (DataChanged != null) { DataChanged(this); } } 样本2 DataChanged.Invoke(this); 我应该在什么时候使用每个方法来调用自定义事件?为什么有时当我尝试使用DataChanged.invoke(this)调用事件时,会出现NullReferenceException,但当我将
public void OnDataChanged()
{
if (DataChanged != null)
{
DataChanged(this);
}
}
样本2
DataChanged.Invoke(this);
我应该在什么时候使用每个方法来调用自定义事件?为什么有时当我尝试使用DataChanged.invoke(this)
调用事件时,会出现NullReferenceException,但当我将事件调用转换为示例1中的方法时,DataChanged
不再为null
当我将事件调用转换为示例1中的方法时,DataChanged永远不会变为Null
然后,您只需查看两种不同的场景
如果不声明类似于
public event EventHandler的事件,那么YourEvent=delegate{}
,则YourEvent
为null
,直到有消费者订阅它。OnXYZ方法应始终遵循以下形式:
public void OnXYZ()
{
var evt = XYZ;
if (evt != null)
evt(sender, e); // where to get e from differs
}
这种形式有几个原因:
public void OnXYZ()
{
var evt = XYZ;
if (evt != null)
evt(sender, e); // where to get e from differs
}
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);
还要注意,在类的外部,事件是一个事件,您只能从中添加或删除事件处理程序
在类内部,事件是一个委托,您可以调用它、检查目标或方法、遍历订阅服务器列表等
此外,在C#6中引入了一个新的运算符,
?。
-基本上是的缩写,如果不为null,则取消引用
,可以缩短此方法:
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
。如果没有订阅数据更改,则会将其设置为null,因此当您尝试执行datachange时。Invoke(此)会得到一个NullRefException,因为它实际上是在尝试执行null.Invoke(此)。附加if(DataChanged!=null)的原因是为了避免在没有人订阅事件时发生这种情况
我不相信当您使用示例1 DataChanged从不为null时,它永远不会到达.Invoke抛出异常。如果没有人订阅,它将始终为空。您确定在示例1中,
数据更改
从不为空吗?或者您只是没有得到NullReference异常(因为您在if
语句中检查DataChanged
是否不是null)
让我们从基础开始。事件是一种特殊的委托。当您调用DataChanged(this)和DataChanged.Invoke(this)时,情况是一样的。为什么?因为它编译成相同的东西。总之,DataChanged(this)
只是调用DataChanged.Invoke(this)
的简写
现在,我们为什么需要检查空引用(如示例1中所示)。
基本上,当您调用一个事件时,您将调用订阅该事件的所有方法(例如,DataChanged+=someEventHandler
)。
如果没有人订阅此事件,它将具有null
值。未分配任何方法来处理此事件。换句话说:事件处理程序为null
这就是为什么在调用事件之前检查null是一种很好的做法 例如:
public void OnAbc(){
var data=Abc;
if(!String.IsNullOrEmpty(data))
Abc(sender,e);
}
在C#6.0中,我建议使用:DataChanged?.Invoke(this)代码>数据更改(此)
只是DataChanged.Invoke(this)的简写代码>他们做同样的事情。