others - 事件和委托在应用程序中有什么区别

请告诉我它们的差异,以及何时使用哪个?有哪些优点和缺点?

什么时候将委托用于事件,反之亦然? 请在生产代码中说明你的真实世界体验。

时间:

什么时候将委托用于事件,反之亦然? 请在生产代码中说明你的真实世界体验。

当我设计自己的API时,我定义作为参数传递给方法的委托,或者类的构造函数:

  • 这个方法可以实现一个简单的'模板方法(例如,Predicate和Action委托被传递给.NET泛型集合类)
  • 或者,类可以执行'回调'(通常是对创建它的类的方法的回调)。

这些委托在运行时通常是不可选的(换句话说,不能是null )。

我倾向于不使用事件; 但是在我使用事件的情况下,我使用它们来选择性地向零个,一个或多个可能感兴趣的客户端发送事件,换句话说,当它有意义时(例如。System.Windows.Form类应该存在,并且运行任何客户端都是否向它事件添加事件处理程序(例如,表单's 'mouse down '事件存在,但是,它是否可选,是否有任何外部客户端有兴趣在该事件上安装事件处理程序)。

事件在元数据中标记为这样。 这允许 Windows 窗体或者 ASP.NET 设计器将事件与委托类型的属性区分开来,并为它们提供适当的支持。

委托类型的另一个区别是用户只能添加和移除事件处理程序,而具有委托类型的属性则可以设置值:


someObj.SomeCallback = MyCallback;//okay, replaces any existing callback
someObj.SomeEvent = MyHandler;//not okay, must use += instead

这有助于隔离事件订阅者: 我可以把我的处理程序添加到一个事件中,你可以将你的处理程序添加到同一个事件,你不会意外覆盖我的处理程序。

为了去了解这些差异,你可以查看以下2个示例,

带有委托(在这种情况下,它是一个不返回值的委托)的示例,


public class Animal
{
 public Action Run {get; set;}

 public void RaiseEvent()
 {
 if (Run != null)
 {
 Run();
 }
 }
}

要使用委托,应该执行如下操作


Animale animal= new Animal();
animal.Run += () => Console.WriteLine("I'm running");
animal.Run += () => Console.WriteLine("I'm still running") ;
animal.RaiseEvent();

这段代码工作正常,但是,可能有一些弱点。

例如,如果我写这个


animal.Run += () => Console.WriteLine("I'm running");
animal.Run += () => Console.WriteLine("I'm still running");
animal.Run = () => Console.WriteLine("I'm sleeping") ;

使用最后一行代码,我只使用一个缺少+ (我使用了+而不是+= )的行为来替代以前的行为,

另一个弱点是,使用Animal类的每个类都可以将RaiseEvent命名为animal.RaiseEvent()

为了避免这种弱点,你可以在c#中使用events

你的动物类会以这种方式改变


public class ArgsSpecial :EventArgs
 {
 public ArgsSpecial (string val)
 {
 Operation=val;
 }

 public string Operation {get; set;}
 } 



 public class Animal
 {
 public event EventHandler<ArgsSpecial> Run = delegate{} //empty delegate. In this way you are sure that value is always != null because no one outside of the class can change it

 public void RaiseEvent()
 { 
 Run(this, new ArgsSpecial("Run faster"));
 }
 }

调用事件


 Animale animal= new Animal();
 animal.Run += (sender, e) => Console.WriteLine("I'm running. My value is {0}", e.Operation);
 animal.RaiseEvent();

差异:

  1. 你没有使用公共属性,而是使用公共字段(使用事件编译器保护你的字段免受不必要的访问),
  2. 事件不能直接指派,在这种情况下,你不能执行先前的错误,因为我已经用重写行为,
  3. 你的类外没有人可以引发事件。
  4. 事件可以包含在接口声明中,而字段则不能,

备注

EventHandler被声明为以下委托:


public delegate void EventHandler (object sender, EventArgs e)

它接受发送方(对象类型)和事件参数,如果发件人来自静态方法,则它为null。

你还可以使用EventHAndler而不是使用EventHandler<ArgsSpecial>

...