[英]Why should I check for null before I invoke the custom event?
What is the difference between these two code samples for invoking an event? 这两个代码示例之间用于调用事件有什么区别?
Sample 1 样品1
public void OnDataChanged()
{
if (DataChanged != null)
{
DataChanged(this);
}
}
Sample 2 样本2
DataChanged.Invoke(this);
When should I use each method to invoke a custom event? 我应该何时使用每种方法来调用自定义事件? And why sometimes I get a NullReferenceException when I try to invoke event using
DataChanged.Invoke(this)
, but when I convert the event invocation to the method in Sample 1 the DataChanged
never becomes null anymore? 为什么有时我尝试使用
DataChanged.Invoke(this)
调用事件时会得到NullReferenceException,但是当我将事件调用转换为示例1中的方法时, DataChanged
永远不会变为null?
An OnXYZ
method should always follow this form: OnXYZ
方法应始终遵循以下形式:
public void OnXYZ()
{
var evt = XYZ;
if (evt != null)
evt(sender, e); // where to get e from differs
}
There are a couple of reasons for this form: 这种形式有几个原因:
if evt != null
check ensures that we don't try to invoke a null
delegate. if evt != null
检查确保我们不会尝试调用null
委托。 This can happen if nobody has hooked up an event handler to the event. evt
, we can safely invoke it after checking for non-null, since nobody can alter it after the if
but before the call. evt
,我们可以在检查非null之后安全地调用它,因为没有人可以在if
但在调用之前改变它。 What to pass for e
differs, if you need to pass an EventArgs
descendant with a parameter there are two ways: e
传递的内容有所不同,如果需要使用参数传递EventArgs
后代,有两种方法:
public void OnXYZ(string p)
{
var evt = XYZ;
if (evt != null)
evt(sender, new SomeEventArgs(p));
}
or more commonly this: 或者更常见的是:
public void OnXYZ(SomeEventArgs e)
{
var evt = XYZ;
if (evt != null)
evt(sender, e);
}
This syntax: 这个语法:
evt(sender, e);
is just a different way of writing this: 只是一种不同的写作方式:
evt.Invoke(sender, e);
Also note that externally to your class, the event is an event, you can only add
or remove
event handlers from it. 另请注意,在您的类外部,事件是一个事件,您只能从中
add
或remove
事件处理程序。
Internal to your class, the event is a delegate, you can invoke it, check the target or method, walk the list of subscribers, etc. 在您的类的内部,事件是委托,您可以调用它,检查目标或方法,遍历订阅者列表等。
Also, in C# 6 there is a new operator introduced, ?.
此外,在C#6中引入了一个新的运算符,
?.
- the Null-conditional operator - which is basically short for if not-null, dereference
, which can shorten this method: - Null条件运算符 - 它基本上是
if not-null, dereference
缩写,可以缩短这个方法:
public void OnXYZ(SomeEventArgs e)
{
var evt = XYZ;
if (evt != null)
evt(sender, e);
}
into this: 进入这个:
public void OnXYZ(SomeEventArgs e)
{
XYZ?.Invoke(sender, e);
}
which can be further shortened with the use of Expression-bodied members: 可以通过使用表达身体成员进一步缩短:
public void OnXYZ(SomeEventArgs e) => XYZ?.Invoke(sender, e);
Please note that it is not possible to write this: 请注意,不能写这个:
XYZ?.(sender, e);
so you must in this case use Invoke
yourself. 所以你必须在这种情况下使用
Invoke
。
when I convert the event invocation to the method in Sample 1 the DataChanged never becomes Null
当我将事件调用转换为示例1中的方法时,DataChanged永远不会变为空
Then you're simply looking at two different scenarios. 然后你只是看两种不同的场景。
if you don't declare an event like public event EventHandler YourEvent = delegate { };
如果你没有声明像
public event EventHandler YourEvent = delegate { };
那样的public event EventHandler YourEvent = delegate { };
, then YourEvent
is null
until some consumer subscribes to it. ,然后
YourEvent
为null
直到某些消费者订阅它。
If nothing has subscribed to DataChanged it will be set to null, and so when you attempt to do DataChanged.Invoke(this) you'll get a NullRefException as really it's trying to do null.Invoke(this). 如果没有订阅DataChanged它将被设置为null,所以当你尝试执行DataChanged.Invoke(this)时,你会得到一个NullRefException,因为它真的试图做null.Invoke(this)。 The reason for the additional if (DataChanged != null) is to avoid this occurring when nobody has subscribed to the event.
附加if(DataChanged!= null)的原因是为了避免在没有人订阅该事件时发生这种情况。
I don't believe that when you use Sample 1 DataChanged is never null, it's just never reaching the .Invoke to throw up the exception. 我不相信当你使用Sample 1 DataChanged永远不会为null时,它永远不会到达.Invoke来抛出异常。 It will always be null if nobody has subscribed.
如果没有人订阅,它将始终为null。
Are you sure, that in Sample 1 the DataChanged
is never null? 您确定,在示例1中,
DataChanged
永远不会为空吗? Or you just don't get the NullReference Exception (because you check if DataChanged
is not null in the if
statement)? 或者你只是没有得到NullReference异常(因为你检查
if
语句中的DataChanged
是否为空 )?
Let's start with the basics. 让我们从基础开始。 Event is a special kind of delegate.
活动是一种特殊的代表。 When you call DataChanged(this) and DataChanged.Invoke(this), it's the same thing.
当你调用DataChanged(this)和DataChanged.Invoke(this)时,它是一样的。 Why?
为什么? Because it compiles to the same thing.
因为它编译成同样的东西。 So all in all the
DataChanged(this)
is just a shorthand for calling DataChanged.Invoke(this)
. 总而言之,
DataChanged(this)
只是调用DataChanged.Invoke(this)
的简写。
Now, why do we need to check for null reference (like in sample 1). 现在,为什么我们需要检查空引用(如示例1中所示)。 Basically, when you invoke an event, you invoke all methods that were subscribed to this event (eg
DataChanged += someEventHandler
). 基本上,当您调用事件时,您将调用订阅此事件的所有方法(例如,
DataChanged += someEventHandler
)。 If nobody subscribed to this event, it will have a null
value. 如果没有人订阅此事件,它将具有
null
值。 No method was assigned to handle this event. 没有分配方法来处理此事件。 In other words: the event handler is null.
换句话说:事件处理程序为null。
That's why it's a good practice to check for null, before invoking an event. 这就是为什么在调用事件之前检查null是一个好习惯。
An Example: 一个例子:
public void OnAbc(){
var data=Abc;
if(!String.IsNullOrEmpty(data))
Abc(sender,e);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.