为什么迫使活动的订阅者在C#中拥有特定的签名?

时间:2016-10-28 09:42:50

标签: c# events delegates

声明一个事件需要订阅者将遵循的代表(据我所知):

public delegate void SomeEventHandler(object source, EventArgs args);
public event SomeEventHandler EventHappend;

但为什么我们需要这个代表呢?为什么不允许任何签名方法订阅该活动?

3 个答案:

答案 0 :(得分:2)

保持你的榜样......

class A
{
  public event EventHappend; // Invalid C# but let's pretend it could work

  public void DoSomething()
  {
    ...
    if (EventHappend != null)
    {
      // What should ??? be replaced with?
      EventHappend(???);
    }
  }
}

class B
{
  public B()
  {
    new A().EventHappend += EventHandler;
  }

  public void EventHandler(int anInt)
  ...
}

class C
{
  public C()
  {
    new A().EventHappend += EventHandler;
  }

  public void EventHandler(string aString)
  ...
}

应该怎么做?被替换为处理B和C的情况(参数中的int或字符串)?

答案 1 :(得分:1)

因为调用者希望能够将一组参数传递给被调用者。因此,调用者和被调用者都需要就某种合同达成一致,该合同定义了调用者期望的参数集以及被调用者提供的参数集 - 恰好是委托者。

"实例"代表说的只不过:看这里,这里是一个"指针"一个符合我签名的方法,并通过调用我可以执行该方法。

示例:调用者想要将自己的实例stringint传递给被调用者。如果被叫方只接受bool

,那该怎么办?

有人可能已经引入了每个事件处理程序需要坚持签名的约定:

public void Method(object sender, EventArgs e);

以便以下事件声明语法始终有效:

public event EventHandler<EventArgs> MyEvent;

但是,如果您想将任何有效负载传递给被调用者,那么在许多情况下这将要求您创建一个派生自EventArgs的类。

答案 2 :(得分:1)

  

为什么不让任何带有任何签名的方法订阅该事件?

那么发件人将如何知道要传递给订阅者的参数?

您可能知道也可能不知道,这就是您提出您在问题中声明的事件的方式:

EventHappened(this, new EventArgs());

每当你举起一个事件时,你需要将参数传递给它!我们假设您允许任何类型的方法订阅该事件,然后我将使用此方法订阅{{ 1}}:

EventHappened

当事件被提出时,会打印什么?没人知道!事件的发送者没有传递一个int参数!

你可能会说

  

然后,当我举起事件时,我只会传递一个额外的int参数!

如果还有其他方法也订阅了该事件,如下所示:

private void Foo(object sender, EventArgs e, int someNumber) {
    Console.WriteLine(someNumber);
}

这样,你的int参数与private void Bar(object sender, EventArgs e, List<string> myList) { Console.WriteLine(myList); } 不兼容!

  

“C#不是Javascript。您不能只将2个参数传递给需要3的方法” - Sweeper 2016

委托类型用于确保事件的发送者传递正确的参数,订阅者是一个可以接受传递的参数作为参数的方法。