我的对象在状态发生变化时会引发StatusChanged事件 - 但是,应用程序需要根据新状态执行其他操作。
例如,如果新状态为Disconnected,则必须更新状态栏文本并发送电子邮件通知。
所以,我想创建一个具有可能状态的Enum(Connected,Disconnected,ReceivingData,SendingData等),并在事件发生时使用事件的EventArgs参数发送(见下文)
定义对象:
class ModemComm
{
public event CommanderEventHandler ModemCommEvent;
public delegate void CommanderEventHandler(object source, ModemCommEventArgs e);
public void Connect()
{
ModemCommEvent(this, new ModemCommEventArgs ModemCommEventArgs.eModemCommEvent.Connected));
}
}
定义新的EventArgs参数:
public class ModemCommEventArgs : EventArgs{
public enum eModemCommEvent
{
Idle,
Connected,
Disconnected,
SendingData,
ReceivingData
}
public eModemCommEvent eventType { get; set; }
public string eventMessage { get; set; }
public ModemCommEventArgs(eModemCommEvent eventType, string eventMessage)
{
this.eventMessage = eventMessage;
this.eventType = eventType;
}
}
然后我在应用程序中为事件创建一个处理程序:
ModemComm comm = new ModemComm();
comm.ModemCommEvent += OnModemCommEvent;
和
private void OnModemCommEvent(object source, ModemCommEventArgs e)
{
}
问题是,当对象尝试引发事件时,我得到“对象引用未设置为对象的实例”错误。希望有人可以用n00b术语解释为什么以及如何解决它:)
答案 0 :(得分:10)
当没有客户端订阅它们时,事件为null,因此尝试调用没有订阅者的事件将因NullReferenceException而失败。
避免这种情况的一些常用技巧:
1)以线程安全的方式检查null(从事件提升者的角度来看;客户端仍有竞争条件,但是他们有责任处理它)
var handler = this.ModemCommEvent;
if( handler != null ) {
handler(this, new ModemCommEventArgs( ModemCommEventArgs.eModemCommEvent.Connected ));
}
以上代码是更复杂的版本:
if( this.ModemCommEvent != null ) {
this.ModemCommEvent(this, new ModemCommEventArgs(ModemCommEventArgs.eModemCommEvent.Connected));
}
第一个(创建一个局部变量)从事件提升者的角度来看更安全,因为局部变量将为null或不会,并且没有任何改变。但是,在第二个中,运行在单独线程上的客户端可以在完成对null的检查和引发事件之间取消订阅事件。在这种情况下,您最终会再次出现NullReferenceException。如果您和您的代码的客户端都没有在多个线程上执行(没有BackgroundWorker,Thread对象,异步调用等),那么更安全的检查是多余的。但是,如果你不确定,这是一个很好的做法。那,或做#2。
2)将您的活动默认为空值
public event CommanderEventHandler ModemCommEvent = delegate { };
这方面通过始终拥有至少一个订户来完全解决问题。 “delegate {}”语法创建一个匿名方法,该方法不执行任何事件的“默认订阅者”。无论有多少客户订阅或取消订阅您的活动,这个匿名方法将始终存在,防止您的活动为空。
-
互联网上已经讨论过这个问题。这是一个这样的例子:
答案 1 :(得分:0)
试
public void Connect()
{
if( ModemCommEvent != null)
ModemCommEvent(this, new ModemCommEventArgs ModemCommEventArgs.eModemCommEvent.Connected));
}
可能,您的Connect是在添加处理程序之前启动的吗?