如何初始化一个事件

5
我有一个类,其中包含以下事件:
public class A
{
    public event Func<string, string> Message;

    public void Calling()
    {
        Message("Hello world!");
    }
}

如果我调用Calling()方法,但是还没有人订阅Message事件,它将为null并抛出异常。

我该如何初始化我的事件?


1
public event Func<string, string> Message = _ => null; - L.B
更深入的有关事件的讨论可以在这里这里找到。 - Jeff B
5个回答

7
您没有初始化事件,而是需要在调用方法中检查是否为空:
public void Calling()
{
    if (Message != null)
        Message("Hello World!");
}

7
事件已经初始化,值为null。解决方法是首先检查null。标准的方法如下所示:
public void Calling()
{
    Func<string, string> handler = Message;

    if (handler != null)
    {
        handler("Hello world!");
    }
}

注意在检查之前,事件值被复制到本地变量中。这可以防止在检查null和调用事件之间发生的并发更改。在许多程序中,这不是必需的(没有并发),您可以直接安全地检查事件本身。
如果您使用支持空条件运算符的C#版本(6.0或更高版本),则可以将上述内容简化为以下形式:
public void Calling()
{
    Message?.Invoke("Hello world!");
}

编译器会为您生成引用的中间副本,检查它是否为null,只有在非null情况下才会调用Invoke()方法。

3

在类中调用事件之前,请检查是否有任何人订阅它以及是否为null

public void Calling()
{
    if (Message != null)
        Message("Hello world!");
}

查看:事件教程

触发一个事件:一旦一个类声明了一个事件,它就可以像使用指定委托类型的字段一样处理该事件。如果没有客户端将一个委托连接到事件上,则该字段将为 null;否则,它会引用一个应在调用事件时调用的委托。因此,触发一个事件通常是首先检查 null,然后调用该事件


1
你不能这样做。
事件默认为null,因此良好的实践要求您在使用它们之前进行检查。
public void Calling()
{
    if (Message != null)
       Message("Hello World");
}

你没有使用返回值,这有点奇怪,但也许只是因为这是一个演示。

你也可以在构造函数中将其初始化为空白函数,但这只会浪费资源:

public A()
{
    Message += (s) => { return String.Empty; };
}

现在每次触发事件都会调用一个无操作的函数,而简单的null检查可以解决这个问题。绝对不建议这样做,但这是"初始化"事件的唯一方法。

1

虽然这不是你的问题,但我会在这里补充一点。您可以通过“空值检查”来检查是否有任何人正在监听事件。这可以确保它不会执行该方法(并随后抛出NullReferenceException异常)。

public void Calling()
{
  if (Message != null)
    Message("Hello World"); // Why are you ignoring the return value?
}

关于你的实际问题,某物必须引用一个类型为A的对象(如你的示例中所定义的)。
public class B
{
  A MyA;

  public B()
  { 
    MyA = new A();
  }
}

然后它必须订阅“消息”事件。
public class B()
{
  A MyA;

  public B()
  { 
    MyA = new A();
    MyA.Message += MessageHandler;
  }

  public string MessageHandler(string s)
  {
    // Do other code here and ensure you're returning a string as defined in your Message event.
    return s;
  }
}

请注意,MessageHandler可以被命名为任何名称。我只是出于清晰起见使用了它。它也可以是匿名方法或Lambda,而不是命名方法。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接