将 EventHandler += EventHandler 添加的效果是什么?

3

我在A类中有一个SelectionChanged事件,我希望通过B类中继承。我曾经以为在B类中声明一个SelectionChanged事件,并将此EventHandler分配给A.SelectionChanged,会导致每当A.SelectionChanged被触发时,B.SelectionChanged也会被触发 - 但事实证明这是错误的。

更清晰一些的代码:

class A
{
   public event EventHandler SelectionChanged;

   public void TriggerSelectionChanged()
   {
      if (SelectionChanged != null) SelectionChanged(this, EventArgs.Empty);
   }
}

class B
{
   private A _a = new A();

   public A A { get { return _a; } }

   public event EventHandler SelectionChanged;

   public B()
   {
      A.SelectionChanged += SelectionChanged;
   }

   public static void Test()
   {
      B relayer = new B();
      bool wasRelayed = false;
      relayer.SelectionChanged += delegate { wasRelayed = true; };
      relayer.A.TriggerSelectionChanged();

      System.Console.WriteLine("Relayed: {0}", wasRelayed);
   }
}

这将打印出“Relayed: false”。 向另一个EventHandler添加EventHandler的效果是什么? 编辑:请注意!我知道解决此问题的方法是通过委托、函数等中继事件,但我更想知道这段代码的影响。
3个回答

2
在这种情况下,B的SelectionChanged和A的SelectionChanged没有关联。
如果您让B继承自A并移除B上的第二个声明,则可以解决此问题。
class A
{
   public EventHandler SelectionChanged;

   public void TriggerSelectionChanged()
   {
      if (SelectionChanged != null) SelectionChanged(this, EventArgs.Empty);
   }
}

class B : A
{
   public static void Test()
   {
      B relayer = new B();
      bool wasRelayed = false;
      relayer.SelectionChanged += delegate { wasRelayed = true; };
      relayer.TriggerSelectionChanged();

      System.Console.WriteLine("Relayed: {0}", wasRelayed);
   }
}

或者您可以通过...

class A
{
   public EventHandler SelectionChanged;

   public void TriggerSelectionChanged()
   {
      if (SelectionChanged != null) SelectionChanged(this, EventArgs.Empty);
   }
}

class B
{
   public B()
   {
     this._a.SelectionChanged += (o, s) => 
     {
       if(this.SelectionChanged != null) { this.SelectionChange(o, s); }
     };
   }




private A _a = new A();

   public A A { get { return _a; } }

   public EventHandler SelectionChanged;

   public static void Test()
   {
      B relayer = new B();
      bool wasRelayed = false;
      relayer.SelectionChanged += delegate { wasRelayed = true; };
      relayer.A.TriggerSelectionChanged();
      System.Console.WriteLine("Relayed: {0}", wasRelayed);
   }

}


1
我认为 OP 想要 B 包含 A,而不是扩展它。 - ColinE
@larsm,我添加了相似的代码来完成你正在尝试的操作。我认为你无法在修改后的代码中实现你想要的功能,需要使用委托。 - Ian
@Ian:那是我的备选方案。然而,我主要关注的是 EventHandler += EventHandler 的效果,而不是其他解决方案。 - larsmoa
@larsm:抱歉,我明白你的意思了。为你自己的答案点一个赞。 - Ian

2
你的代码中没有任何东西将 B.SelectionChanged 的调用与 A.SelectionChanged 相连接。因此,当你在 A 上触发 SelectionChanged 时,处理 B 上的 SelectionChanged 的委托不会被调用。
我认为你想要的是让 B 上的事件作为 A 公开的事件的适配器?如果是这样的话,你需要编写自己的 add/remove 逻辑。请参见以下内容:

事件 + 适配器模式

另一个 add/remove 的示例:

C#: 带有显式 add/remove 的事件 != 典型事件?


我忘记添加将B连接到A的构造函数,已经编辑了问题。 - larsmoa

1
原来这是 EventHandler 是 Delegate 的一个效果。该类通过(或者我认为是)使用 Delegate.Combine 实现了 operator +=。该函数的文档如下:

连接指定多路广播(可组合)委托的调用列表。

发生的情况是,右侧分配给 EventHandler 的所有处理程序都添加到左侧的 EventHandler 中。在这种情况下,没有处理程序,因此什么也不会发生。但是,如果更改事物的顺序,使得在将 B.SelectionChanged 连接到 A.SelectionChanged 之前分配 B.SelectionChanged,则可以正确地连接它们。但是,从 B 中删除处理程序不会从 A 中删除它,因此应该严格禁止这样做。

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