委托和事件之间的区别是什么?两者不都持有可以执行的函数的引用吗?
当前回答
为了理解它们的区别,你可以看看这两个例子
委托的示例(在本例中是Action -这是一种不返回值的委托)
public class Animal
{
public Action Run {get; set;}
public void RaiseEvent()
{
if (Run != null)
{
Run();
}
}
}
要使用委托,你应该这样做:
Animal 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类的类都可以直接调用委托。例如,Animal . run()或Animal . run . invoke()在Animal类之外有效。
为了避免这些弱点,你可以在c#中使用事件。
你的动物职业会这样改变:
public class ArgsSpecial : EventArgs
{
public ArgsSpecial (string val)
{
Operation=val;
}
public string Operation {get; set;}
}
public class Animal
{
// Empty delegate. In this way you are sure that value is always != null
// because no one outside of the class can change it.
public event EventHandler<ArgsSpecial> Run = delegate{}
public void RaiseEvent()
{
Run(this, new ArgsSpecial("Run faster"));
}
}
调用事件
Animal animal= new Animal();
animal.Run += (sender, e) => Console.WriteLine("I'm running. My value is {0}", e.Operation);
animal.RaiseEvent();
差异:
You aren't using a public property but a public field (using events, the compiler protects your fields from unwanted access) Events can't be assigned directly. In this case, it won't give rise to the previous error that I have showed with overriding the behavior. No one outside of your class can raise or invoke the event. For example, animal.Run() or animal.Run.Invoke() are invalid outside the Animal class and will produce compiler errors. Events can be included in an interface declaration, whereas a field cannot
注:
EventHandler被声明为如下委托:
public delegate void EventHandler (object sender, EventArgs e)
它接受一个发送者(Object类型)和事件参数。如果来自静态方法,则发送者为空。
这个例子使用了EventHandler<ArgsSpecial>,也可以使用EventHandler来代替。
请参阅这里有关EventHandler的文档
其他回答
您还可以在接口声明中使用事件,但委托则不是这样。
除了语法和操作属性之外,还有语义上的差异。
从概念上讲,委托是函数模板;也就是说,它们表达了一个函数必须遵守的契约,以便被认为是委托的“类型”。
事件代表……嗯,事件。它们的目的是在发生事情时提醒某人,是的,它们遵循委托定义,但它们不是同一件事。
即使它们是完全相同的东西(在语法上和IL代码中),仍然会存在语义差异。一般来说,我更喜欢对两个不同的概念使用两个不同的名称,即使它们以相同的方式实现(这并不意味着我喜欢使用两次相同的代码)。
Delegate是一个类型安全的函数指针。事件是使用委托的发布者-订阅者设计模式的实现。
Event声明在委托实例上添加了一层抽象和保护。此保护可防止委托的客户端重置委托及其调用列表,并且仅允许从调用列表中添加或删除目标。
An event in .net is a designated combination of an Add method and a Remove method, both of which expect some particular type of delegate. Both C# and vb.net can auto-generate code for the add and remove methods which will define a delegate to hold the event subscriptions, and add/remove the passed in delegagte to/from that subscription delegate. VB.net will also auto-generate code (with the RaiseEvent statement) to invoke the subscription list if and only if it is non-empty; for some reason, C# doesn't generate the latter.
Note that while it is common to manage event subscriptions using a multicast delegate, that is not the only means of doing so. From a public perspective, a would-be event subscriber needs to know how to let an object know it wants to receive events, but it does not need to know what mechanism the publisher will use to raise the events. Note also that while whoever defined the event data structure in .net apparently thought there should be a public means of raising them, neither C# nor vb.net makes use of that feature.
推荐文章
- 何时使用IList,何时使用List
- ConfigurationManager。AppSettings在.NET Core 2.0中可用?
- 在c#的控制台应用程序中使用'async
- 在单元测试中设置HttpContext.Current.Session
- 如何开始开发Internet Explorer扩展?
- 更新行,如果它存在,否则插入逻辑实体框架
- 在什么情况下SqlConnection会自动被征召到环境事务范围事务中?
- 用c#解析JSON
- Windows窗体中的标签的换行
- 为什么在c#中使用finally ?
- 为什么我不能在c#中有抽象静态方法?
- net HttpClient。如何POST字符串值?
- 删除绑定中添加的事件监听器
- 我如何使一个方法的返回类型泛型?
- 何时处理CancellationTokenSource?