Action <T> vs委托事件

Bha*_*kar 58 c# delegates

我见过开发人员使用下面的代码.它们之间的确切区别是什么,哪些符合标准?他们是一样的,Action而且Func<T>是一个代表,以及:

public event Action<EmployeeEventAgs> OnLeave;
public void Leave()
{
    OnLeave(new EmployeeEventAgs(this.ID));
}
Run Code Online (Sandbox Code Playgroud)

VS

public delegate void GoOnLeave(EmployeeEventAgs e);
public event GoOnLeave OnLeave;
public void Leave()
{
    OnLeave(new EmployeeEventAgs(this.ID));
}
Run Code Online (Sandbox Code Playgroud)

Han*_*ant 51

Fwiw,这两个例子都没有使用标准的.NET约定.在EventHandler<T>一般的应申报的事件:

public event EventHandler<EmployeeEventArgs> Leave;
Run Code Online (Sandbox Code Playgroud)

应该为引发事件的受保护方法保留"On"前缀:

protected virtual void OnLeave(EmployeeEventArgs e) {
    var handler = Leave;
    if (handler != null) handler(this, e);
}
Run Code Online (Sandbox Code Playgroud)

你不具备做这种方式,但任何人一眼就能认出的模式,理解你的代码,并知道如何使用和定制.

并且它具有很大的优势,即不必被迫在自定义委托声明之间进行选择Action<>,这EventHandler<>是最好的方法.哪个回答你的问题.

  • 这是一个很好的建议,但我不认为它回答了这个问题 (39认同)
  • 不,那是一个错误.三年内没人注意到:)谢谢! (3认同)
  • 您是否将`Leave`处理程序声明为委托,而不是:public __event__ EventHandler <> ......故意?当你使用暴露事件的类时,`event`关键字是一个游戏改变者,因为没有它可以通过使用`obj.Leave = someHandler`而不是`obj.Leave + = someHandler来简单地消灭整个事件集合. ` (2认同)

Iva*_*vov 28

以下两行代码几乎相同:

public event Action<EmployeeEventAgs> Leave;
Run Code Online (Sandbox Code Playgroud)

相比:

public event EventHandler<EmployeeEventAgs> Leave;
Run Code Online (Sandbox Code Playgroud)

不同之处在于事件处理程序方法的签名.如果您对该操作使用第一种方法,则可以:

public void LeaveHandler(EmployeeEventAgs e) { ... }
Run Code Online (Sandbox Code Playgroud)

然后这个:

obj.Leave += LeaveHandler;
Run Code Online (Sandbox Code Playgroud)

使用第二种方法,LeaveHandler需要的签名是不同的:

public void LeaveHandler(object sender, EmployeeEventAgs e) { ... }
Run Code Online (Sandbox Code Playgroud)

请注意,在这两种情况下,关键字都用于声明事件成员,这一点非常重要event.以这种方式声明的事件成员不仅仅是类的一个字段,尽管看起来好像是这样.相反,编译器将其创建为事件属性1.事件属性类似于常规属性,除了它们没有getset访问者.编译器允许它们仅在a +=-=赋值的左侧使用(添加或删除事件处理程序).无法覆盖已分配的事件处理程序,也无法在声明的类之外调用事件.

如果两个示例中都缺少event关键字,则可以执行以下操作,不会出现错误或警告:

obj.Leave = LeaveHandler;
Run Code Online (Sandbox Code Playgroud)

这将删除任何已注册的处理程序并替换它们LeaveHandler.

此外,您还可以执行此调用:

obj.Leave(new EmployeeEventAgs());
Run Code Online (Sandbox Code Playgroud)

如果您打算创建事件,则上述两种情况被视为反模式.应仅由所有者对象调用事件,并且不应允许无法删除订阅者.该event关键字是.NET的编程结构,它可以帮助你坚持正确的使用事件.

考虑到上述情况,我相信很多人都坚持这种EventHandler方法,因为EventHandler没有event关键字更不可能使用.操作具有更广泛的使用范围,当用作事件时它们看起来不那么自然.当然,后者是个人意见,因为事件处理程序方法在我自己的编码实践中可能变得太硬.但是,如果正确使用行动,将它们用于事件并非犯罪行为.


1事件属性是编译器在看到如下代码时自动生成的:

event EventHandler SomeEvent 
Run Code Online (Sandbox Code Playgroud)

它与下面的代码大致相同:

private EventHandler _someEvent; // notice the lack of the event keyword!
public event EventHandler SomeEvent
{
    add { _someEvent += value; }
    remove { _someEvent -= value; }
}
Run Code Online (Sandbox Code Playgroud)

我们写的事件调用如下:

this.SomeEvent(sender, args);
Run Code Online (Sandbox Code Playgroud)

转换成这个:

this._someEvent(sender, args);
Run Code Online (Sandbox Code Playgroud)

  • +1为详细说明。 (3认同)

pdr*_*pdr 22

Action<T> 与...完全相同 delegate void ... (T t)

Func<T> 与...完全相同 delegate T ... ()

  • 这会使它们不完全一样吗?这里X和Y是不同的:public delegate void X <T>(T t); public delegate void Y <T>(T t); 您不能将一个分配给另一个. (4认同)
  • 不*完全相同*...它们确实具有相同的签名,但它们不兼容分配(恕我直言,这是非常不幸的...) (2认同)

Dar*_*ten 6

Action只是完整委托声明的捷径.

public delegate void Action<T>(T obj)
Run Code Online (Sandbox Code Playgroud)

http://msdn.microsoft.com/en-us/library/018hxwa8.aspx

使用哪一个取决于您的组织编码标准/风格.


Sky*_*ers 5

是的,Action 和 Func 只是 3.5 clr 中定义的方便委托。

Action、Func 和 lambda 都只是语法糖,方便使用委托。

它们没有什么神奇之处。有几个人编写了简单的 2.0 插件库来将此功能添加到 2.0 代码中。


Nic*_*ver 5

你可能想看看这里,看看编译器实际为 Action 生成的内容是最好的描述。您编写的内容没有功能上的差异,只是更短、更方便的语法。