分配 Action<T> 方法和订阅 Action<T> 事件的区别

6
假设我有下面的代码。直接分配操作和订阅事件之间有什么区别?
//Action directly assigned
public class ClassA
{
  public Action<string> OnAdd;

  private void SomethingHappened()
  {
     OnAdd("It Happened");
  }
}

public class ClassB
{

  public ClassB()
  {
    var myClass = new ClassA();
    myClass.OnAdd =  Add;
  }

  private void Add(string Input)
  {
    //do something
  }  
}

//Event handlers
public class ClassA
{
  public event Action<string> OnAdd;

  private void SomethingHappened()
  {
    if (OnAdd != null)
     OnAdd("It Happened"); //Should it be OnAdd.Invoke("It Happened") ???????
  }
}

public class ClassB
{

  public ClassB()
  {
    var myClass = new ClassA();
    myClass.OnAdd += Add;
  }

  private void Add(string Input)
  {
    //do something
  }  
}

通常情况下,您会使用EventArgs<yourCustomEventArgs>创建事件,而不是使用Action。 - Ignacio Soler Garcia
@SoMoS 即使只是传递一个字符串或整数? - Jon
@jon 这行代码 myClass.Add = myClass.OnAdd; 是无效的... .Add 是指什么? - Royi Namir
@RoyiNamir 谢谢,发现得好。我已经修改了代码。 - Jon
@jon 请查看推荐的设计模式 http://i.stack.imgur.com/LeUSA.jpg - Royi Namir
@Jon,是的,即使只是一个字符串。更重要的是,当您不传递任何内容时,模式表明您应该遵守对象发送器,EventArgs e签名。 - Ignacio Soler Garcia
3个回答

11
(另外一件事,当你使用相同的类型名称两次时,解释起来很困难。)
当您使用公共字段时,客户端不仅可以订阅事件,还可以通过赋值而不是添加完全删除其他事件处理程序:
myClass.OnAdd = Add;

他们也可以直接调用处理程序:

myClass.OnAdd("foo");

这两者都违反了正常的发布/订阅模式,其中各个订阅者是相互隔离的。订阅者不能覆盖彼此的订阅(只能添加或删除自己的订阅),也不能自行引发事件。

有关事件和委托的更多信息,请参见我关于该主题的文章


从你的书中读取 - 事件类似于代理链的属性(getter setter),它就像另一种保护级别,不允许用户使用“=”。 (附言:你昨天发给我的种子文件大小为50GB!但这是值得的... :)) - Royi Namir
@JonSkeet 感谢您的答案,使用相同的名称说明了问题的要点 - 两个看起来非常相似的东西有什么区别。 - Jon
@RoyiNamir 我认为这是针对 @JonSkeet 的?虽然是一个合理的问题。无论写什么都将是公开的。 - Jon
@RoyiNamir:不,使用event关键字时,它不会成为公共字段,而是一个带有私有基础字段的公共事件 - Jon Skeet
@Jon:但当我尝试描述事物之间的差异时,能够引用不同的名称会很有帮助,例如 ClassWithFieldClassWithEvent - Jon Skeet
显示剩余3条评论

2
你可以为一个事件分配多个委托(使用+=操作符)。

1
如果你只有一个委托字段,你也可以创建复合事件... 重点是使用事件时,你只需要添加处理程序,而不是覆盖现有的处理程序。 - Jon Skeet

0
一个事件(Event)就像是一个包装器,用来保护代表(Delegate)免受重新分配或删除的影响,正如 John 所指出的那样。我发现 this 非常有意思。

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