C# 触发事件时出现NullReferenceException
我有这段代码,但至少对我来说,这会导致一个奇怪的异常C# 触发事件时出现NullReferenceException,c#,.net,events,nullreferenceexception,C#,.net,Events,Nullreferenceexception,我有这段代码,但至少对我来说,这会导致一个奇怪的异常 public class Flight { public class MessageEventArgs : System.EventArgs { public string msgContent; } public event System.EventHandler LogMessage; public void StartFlight() { string
public class Flight
{
public class MessageEventArgs : System.EventArgs
{
public string msgContent;
}
public event System.EventHandler LogMessage;
public void StartFlight()
{
string tmpDeparture = this.Departure;
string tmpDestination = this.Destination;
this.OnLogUpdate("Taking off from " + tmpDeparture + " now.");
this.Destination = tmpDeparture;
Thread.Sleep(1000);
this.OnLogUpdate("Arriving in " + tmpDestination + " now.");
this.Departure = tmpDestination;
}
protected virtual void OnLogUpdate(string logMessage)
{
MessageEventArgs e = new MessageEventArgs();
if (logMessage == "")
return;
e.msgContent = logMessage;
LogMessage(this, e);
}
}
它会在,
日志消息(本,e)
我不明白,当我在另一个类中有一个几乎相同的设置并且运行良好时,为什么会导致上述异常。
此外,在使用变量检查器进行检查时,设置了this
和e
,因此不为空
我对C#还是有点陌生,尤其是事件和代表,所以我可能错过了一些或多或少明显的东西
[编辑]
如果是因为事件没有订阅,那么这有什么问题
public partial class MainForm : Form
{
Airport airport = new Airport();
Flight flight = new Flight();
public MainForm()
{
InitializeComponent();
InitializeEvents();
}
private void InitializeEvents()
{
this.airport.ErrorMessage += new System.EventHandler(OnErrorReceived);
this.flight.LogMessage += new System.EventHandler(OnLogReceived);
}
机场错误消息的订阅工作正常,但航班日志消息的订阅工作不正常?日志消息是一个事件,未被其他类订阅。您应该在触发它之前检查它是否为null
if (LogMessage != null)
{
LogMessage(this, e);
}
LogMessage是一个事件,未被其他类订阅。您应该在触发它之前检查它是否为null
if (LogMessage != null)
{
LogMessage(this, e);
}
我建议将这一行添加到您的
Flight
对象构造函数中
LogMessage += (s, o) => {};
这将向您的事件添加一个虚拟处理程序,您可以使用它,而无需每次都检查它的可空性,但它有很高的开销,如果有人将LogMessage
设置为空,则会发出隆隆声<代码>NullPointerException
另一个选项是在每次要触发事件时检查可空性
if(LogMessage != null)
{
LogMessage(this, e);
}
但是,当线程A检查LogMessage
是否为null且不为null,线程B将LogMessage
设置为null,然后线程A触发LogMessage
并启动时,这可能会造成多线程场景中的争用条件<代码>空点异常
最好的办法就是这样做
protected virtual void OnLogUpdate(string logMessage)
{
if (logMessage == "")
return;
MessageEventArgs e = new MessageEventArgs();
var handler = LogMessage;
if (handler != null)
{
e.msgContent = logMessage;
handler(this, e);
}
}
我建议将这一行添加到您的
Flight
对象构造函数中
LogMessage += (s, o) => {};
这将向您的事件添加一个虚拟处理程序,您可以使用它,而无需每次都检查它的可空性,但它有很高的开销,如果有人将LogMessage
设置为空,则会发出隆隆声<代码>NullPointerException
另一个选项是在每次要触发事件时检查可空性
if(LogMessage != null)
{
LogMessage(this, e);
}
但是,当线程A检查LogMessage
是否为null且不为null,线程B将LogMessage
设置为null,然后线程A触发LogMessage
并启动时,这可能会造成多线程场景中的争用条件<代码>空点异常
最好的办法就是这样做
protected virtual void OnLogUpdate(string logMessage)
{
if (logMessage == "")
return;
MessageEventArgs e = new MessageEventArgs();
var handler = LogMessage;
if (handler != null)
{
e.msgContent = logMessage;
handler(this, e);
}
}
你能把它缩小到最小的代码集吗@完成后,删除了大部分不相关的代码(至少与此问题无关)'LogMessage'是一个事件。如果没有人订阅该事件,则该事件将为null。几乎所有的
NullReferenceException
情况都是相同的。请参阅“”,以获得一些提示。@JohnSaunders我已经看过了,这并不是说我不知道通常是什么导致了NullReferenceException,但这种情况有所不同,我想……你能把它缩小到最小的代码集吗@完成后,删除了大部分不相关的代码(至少与此问题无关)'LogMessage'是一个事件。如果没有人订阅该事件,则该事件将为null。几乎所有的NullReferenceException
情况都是相同的。请参阅“”,以获得一些提示。@JohnSaunders我已经看过了,这并不是说我不知道通常是什么导致了NullReferenceException,但这种情况是不同的,我认为……好的,这修复了异常,谢谢!虽然我不明白为什么它没有被订阅properlyEvent是引用类型,但如果您没有为它设置值,它将为null。您应该在其他类中订阅它,如:Flight Flight=new Flight()Flight.LogMessage+=Func;这将把值设置为LogMessage.and赋值后不为null这不是线程安全好的,修复了异常,谢谢!虽然我不明白为什么它没有被订阅properlyEvent是引用类型,但如果您没有为它设置值,它将为null。您应该在其他类中订阅它,如:Flight Flight=new Flight()Flight.LogMessage+=Func;这会将值设置为LogMessage.and它在赋值后不为null这不是线程安全的谢谢,是的,这一切都是有意义的,除了它为null的原因之外,我仍然不明白,因为我订阅了它,就像订阅了另一个类的类似事件一样。可能StartFlight()
在按下按钮调用InitializeEvents
StartFlight()之前被调用,其中InitializeEvents在加载表单的同时被调用。我在Airport ErrorMessage上有一个几乎相同的按钮,效果很好。你应该在代码中跟踪OnLogUpdate
调用,我想在InitializeEvents
之前调用OnLogUpdate
当我在InitializeEvents上设置断点时,它会在我运行调试会话时暂停,因为它在那里进行初始化。当我在OnLogUpDead上有一个断点时,它首先停顿,当我按下我用来触发该方法的按钮时,它仍然认为该日志消息是NullThanks,并且这一切都是有意义的,除了它是空的原因之外,我仍然不明白。因为我订阅了它,就像订阅了另一个类中的类似事件一样。在按下按钮调用InitializeEvents
StartFlight()之前,可能会调用StartFlight()
,在加载表单的同时调用InitializeEvents()。我在Airport ErrorMessage上有一个几乎相同的按钮,效果很好。你应该在代码中跟踪OnLogUpdate
调用,我想在InitializeEvents
之前调用OnLogUpdate
当我在InitializeEvents上设置断点时,它会在我运行调试会话时暂停,因为它在那里进行初始化。当我在OnLogUpdate上有一个断点时,当我按下用于触发该方法的按钮时,它首先暂停,此时