【问题标题】:Error when raising custom event引发自定义事件时出错
【发布时间】:2016-12-15 12:50:55
【问题描述】:

我有一个会写日志的课程。该类需要引发一个事件(在下面未说明的特定情况下),该事件将由一个类对其做出反应。我有下面的代码,但是一旦我尝试引发事件,我就会在指示的行上收到一个错误,即

对象引用未设置为对象的实例

知道我错过了什么吗?

//1. Class where event is registered
    public class LogEvent
    {
        public delegate void WriteLogEventHandler(object Sender, WriteLogEventArgs e);
        public event WriteLogEventHandler WriteLog;

        public class WriteLogEventArgs : EventArgs
        {
            public string Message { get; set; }

            public WriteLogEventArgs(string message) : base()
            {
                Message = message;
            }
        }

        //Raise the event.
        internal void OnWriteLog(WriteLogEventArgs e)
        {
             WriteLog(this, e);    //Error here.  Seems like WriteLog is null
        }

//2. Class where event is raised.
public class Logs
{
    public static void WriteLog(string message)
    {
        LogEvent.WriteLogEventArgs args = new LogEvent.WriteLogEventArgs(message);
        new LogEvent().OnWriteLog(args);
    }
}

//3. Class where event should be consumed
public class MyClass()
{
    private LogEvent _logEvent;
    public MyClass()
        {
            //Subscribe to event:
            _logEvent = new LogEvent();
            _logEvent.WriteLog += (sender, args) => { DoSomething(args.Message); };
        }

   public void DoSomething(string message)
   { ... }
}

【问题讨论】:

  • 当您在WriteLog(string message) 中执行new LogEvent().OnWriteLog(args); 时,您会创建一个新的LogEvent 实例,它没有将WriteLog 连接到处理程序,所以它当然仍然为空。同样在MyClass 构造函数中,您创建一个LogEvent 并连接WriteLog,但不要在任何地方存储LogEvent 的实例。
  • 有道理。我有这样的想法,并尝试了一些场景,但还没有成功。我觉得要求代码示例太愚蠢了,所以我现在继续尝试:)
  • 您的答案的第 2 部分部分在我的代码中,但不在问题中。将更新问题。谢谢。

标签: c# events delegates custom-events


【解决方案1】:

两个问题:

  • 无论是否有人订阅,您都在发起该事件。不要那样做 - 如果您在 WriteLog 为空时调用 WriteLog(this, e),您得到一个 NullReferenceException。在 C# 6 中很容易避免这种情况:

    WriteLog?.Invoke(this, e);
    
  • 您在与引发事件的实例不同的LogEvent 实例上订阅事件。这更像是一个设计问题——单个日志事件拥有订阅者列表是没有意义的。相反,您应该有一个 Logger 或类似的有订阅者(通过事件),然后每个 LogEvent 被传递给这些订阅者。您将创建一个 Logger,订阅它,然后在同一个实例上调用WriteLog

【讨论】:

  • 第 1 点非常方便,谢谢(虽然它应该是 WriteLog?.Invoke 而不是 WriteLine.Invoke)。第2点我还不确定如何解决。根据对迈克尔的反馈,我觉得要求代码示例太愚蠢了,所以我现在会继续尝试:)。感谢您的回答。
猜你喜欢
  • 2021-02-24
  • 1970-01-01
  • 1970-01-01
  • 2017-05-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-25
相关资源
最近更新 更多