C#事件,那个null的东西是什么?

我无法真正理解在提升事件时这个空测试的东西是什么。

说我有这个代码。

class ballClass { public event EventHandler BallInPlay; public void onHit() { if (BallInPlay != null) { BallInPlay(this, new EventArgs()); } else { MessageBox.Show("null!"); } } } 

而且我想在触发onHit()方法时引发BallInPlay。

现在它告诉我BallInPlay是null。 我应该怎样或者用什么“填充”它才能起作用?

谢谢!

您需要使用处理程序订阅该事件。 例如:

 BallClass ball = new BallClass(); ball.BallInPlay += BallInPlayHandler; // Now when ball.OnHit is called for whatever reason, BallInPlayHandler // will get called ... private void BallInPlayHandler(Object sender, EventArgs e) { // React to the event here } 

有关更多信息,您可能需要阅读有关事件和委托的文章 。

请注意,我已经修复了上面的BallClassOnHit – 最好使用标准的.NET命名约定来使代码更好地适应它周围的代码,并使其对其他人更具可读性。

有一点需要注意:您目前所获得的无效检查不是线程安全的。 最后一个订阅者可以 if但在调用之前取消订阅。 线程安全的版本是:

 public void OnHit() { EventHandler handler = BallInPlay; if (handler != null) { handler(this, new EventArgs()); } else { MessageBox.Show("null!"); } } 

这不能保证使用最新的订阅者(因为没有涉及内存障碍),但保证不会因竞争条件而抛出NullReferenceException。

这里的事情是,如果注册零监听器来监听此事件被引发,则该事件为空。 如果一个或多个听众被注册,它将具有一个值。

这意味着如果注册了零侦听器,并且您尝试在不执行空检查的情况下引发事件,则程序将抛出异​​常。

null测试是因为如果NOONE正在侦听事件,那么你swuold调用的事件对象实际上是null。 因此,没有订阅者,您将获得空指针exception。

如果没有为事件分配事件处理程序,则事件为null。 将事件视为List,当列表中没有项目时,事件的值变为null

在没有为其分配事件处理程序时尝试调用事件将引发NullReferenceException。

空检查可防止NullReferenceException。

如果你想让BallInPlay工作,你需要添加一个EventHandler

你的代码将是这样的:

BallInPlay += new EventHandler(YourFunctionNameGoesHere);

空测试用于确定是否有任何内容正在侦听事件。 一旦某事附加了事件处理程序,BallInPlay将不再为null

 BallInPlay(this, new EventArgs()); 

一旦您意识到上面的代码行实际编译好,就好像您已经编写了以下代码,那么在触发事件之前进行null检查的原因就会变得很明显:

 BallInPlay.Invoke(this, new EventArgs()); // ^^^^^^^ 

众所周知,在null引用上调用方法是个坏主意。 这就是为什么你需要首先检查BallInPlay != null


其他建议:

  • 使用EventArgs.Empty而不是new EventArgs()

  • 如果您按如下方式初始化BallInPlay ,则可以绕过检查null

    public event EventHandler BallInPlay = delegate { } ;

    这是有效的,因为现在总是有一个订阅此事件的“空”处理程序方法。 因此,您可以保证在初始化后事件委托不再为null 。 (有些人可能认为这效率稍低。)

    您始终可以使用BallInPlay事件中的+=-=运算符订阅或取消订阅事件处理程序; 例如:

    ball.BallInPlay += (sender, e) => { /* react to the triggered event */ };

  • 我认为你的onHit (或者更确切地说,如果我们遵守.NET世界中常见的约定, OnHit方法不应该是公开的 ,因为这反映了事件的整个目的。 事件实际上是委托,但有一些额外的限制。 一个这样的限制是只有定义事件的类才能调用(“触发”)它。 另一方面,代表可以被任何人援引。 因此,如果你将onHit公开,从而允许任何人触发你的事件,你也可以将BallInPlay定义为委托,即没有event关键字。

  • onHit事件触发器方法的线程安全实现如下所示。 请注意,在方法内部使用事件处理程序委托的本地副本。 这是为了确保在检查null和调用之间不会修改事件处理程序(例如,通过另一个线程)。


 protected virtual void OnHit() { EventHandler handler = BallInPlay; // use a local copy of the event if (handler != null) // for better thread-safety! { handler(this, EventArgs.Empty); } } 
 BallInPlay += new EventHandler(myFunc); public void myFunc(object sender, EventArgs e) { MessageBox.Show("Woho \o/"); }