我无法真正理解在举起活动时这个空测试的东西是什么。
说我有这段代码。
class ballClass
{
public event EventHandler BallInPlay;
public void onHit()
{
if (BallInPlay != null)
{
BallInPlay(this, new EventArgs());
}
else
{
MessageBox.Show("null!");
}
}
}
即使触发了onHit()方法,我想提出一个BallInPlay。
现在它告诉我BallInPlay是null。怎么或用什么来“填充”它才能起作用?
谢谢!
答案 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。
请注意,我已经修复了上面BallClass
和OnHit
的大小写 - 最好使用标准的.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/");
}