行动<t>与委托事件</t>

时间:2010-02-17 16:36:21

标签: c# delegates

我见过开发人员使用以下代码。它们之间的确切区别是什么,哪些符合标准?它们是否相同,因为ActionFunc<T>也是代理人:

public event Action<EmployeeEventAgs> OnLeave;
public void Leave()
{
    OnLeave(new EmployeeEventAgs(this.ID));
}

VS

public delegate void GoOnLeave(EmployeeEventAgs e);
public event GoOnLeave OnLeave;
public void Leave()
{
    OnLeave(new EmployeeEventAgs(this.ID));
}

8 个答案:

答案 0 :(得分:50)

Fwiw,这两个例子都没有使用标准的.NET约定。 EventHandler<T>泛型应该声明事件:

public event EventHandler<EmployeeEventArgs> Leave;

“On”前缀应保留用于引发事件的受保护方法:

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

你没有这样做,但任何人都会立即识别模式,理解你的代码并知道如何使用和定制它。

它的最大优点是不必在自定义委托声明和Action<>之间进行选择,EventHandler<>是最好的方法。哪个回答你的问题。

答案 1 :(得分:27)

以下两行代码几乎相同:

public event Action<EmployeeEventAgs> Leave;

与之相比:

public event EventHandler<EmployeeEventAgs> Leave;

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

public void LeaveHandler(EmployeeEventAgs e) { ... }

然后这个:

obj.Leave += LeaveHandler;

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

public void LeaveHandler(object sender, EmployeeEventAgs e) { ... }

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

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

obj.Leave = LeaveHandler;

删除所有已注册的处理程序并将其替换为LeaveHandler

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

obj.Leave(new EmployeeEventAgs());

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

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


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

event EventHandler SomeEvent 

它与以下代码大致相同:

private EventHandler _someEvent; // notice the lack of the event keyword!
public event EventHandler SomeEvent
{
    add { _someEvent += value; }
    remove { _someEvent -= value; }
}

我们写的事件调用:

this.SomeEvent(sender, args);

转换为:

this._someEvent(sender, args);

答案 2 :(得分:21)

Action<T>delegate void ... (T t)

完全相同

Func<T>delegate T ... ()

完全相同

答案 3 :(得分:6)

行动只是完整委托声明的捷径。

public delegate void Action<T>(T obj)

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

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

答案 4 :(得分:4)

是的,Action和Func只是在3.5 clr。

中定义的便利代表

Action,Func和lambdas都只是语法糖和使用委托的便利。

他们没有什么魔力。有些人编写了简单的2.0插件库来将此功能添加到2.0代码中。

答案 5 :(得分:4)

You may want to look here ,看看编译器为Action实际生成的内容是最佳描述。你所写的内容没有功能上的区别,只是更短,更方便的语法。

答案 6 :(得分:3)

一般来说,它们是等价的。但是在使用委托作为事件类型的上下文中,约定是使用EventHandler(其中T继承EventArgs):

public event EventHandler<EmployeeEventArgs> Left;

public void Leave()
{
    OnLeft(this.ID);
}

protected virtual void OnLeft(int id)
{
    if (Left != null) {
        Left(new EmployeeEventArgs(id));
    }
}

答案 7 :(得分:0)

你可以自己编写这些Action和Func泛型代理,但由于它们通常很有用,所以它们会为你编写它们并将它们放在.Net库中。