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

时间:2011-01-28 07:58:26

标签: c# events

我无法真正理解在举起活动时这个空测试的东西是什么。

说我有这段代码。

    class ballClass
{


    public event EventHandler BallInPlay;


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



}

即使触发了onHit()方法,我想提出一个BallInPlay。

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

谢谢!

7 个答案:

答案 0 :(得分:9)

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

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

答案 1 :(得分:7)

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

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
}

有关详细信息,您可能需要阅读我的article on events and delegates

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

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

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

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

答案 2 :(得分:2)

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

答案 3 :(得分:2)

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

如果没有为其分配事件处理程序,则尝试调用事件将引发NullReferenceException。

空检查可防止NullReferenceException。

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

您的代码将是这样的:

BallInPlay += new EventHandler(YourFunctionNameGoesHere);

答案 4 :(得分:1)

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

答案 5 :(得分:1)

BallInPlay(this, new EventArgs());

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

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

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


其他建议:

  • 使用EventArgs.Empty代替new EventArgs()

  • 如果您按如下方式初始化null,则可以绕过BallInPlay的支票:

    public event EventHandler BallInPlay = delegate { } ;

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

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

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

  • 我认为您的onHit (或者更确切地说,OnHit如果我们遵守.NET世界中常见的约定 方法不应该是公开的,因为这会对抗事件的整个目的。事件实际上是委托,但有一些额外的限制。一个这样的限制是只有定义事件的类才能调用(“触发”)它。另一方面,代表可以被任何人援引。因此,如果您将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);
    }
}

答案 6 :(得分:0)

BallInPlay += new EventHandler(myFunc);

public void myFunc(object sender, EventArgs e)
{
MessageBox.Show("Woho \o/");
}