代表和事件之间有什么区别?

本文翻译自:What are the differences between delegates and events?

What are the differences between delegates and an events? 代表和事件之间有什么区别? Don't both hold references to functions that can be executed? 两者都不都包含对可以执行的功能的引用吗?


#1楼

参考:https://stackoom.com/question/7aF/代表和事件之间有什么区别


#2楼

Here is another good link to refer to. 这是另一个值得参考的链接。 http://csharpindepth.com/Articles/Chapter2/Events.aspx http://csharpindepth.com/Articles/Chapter2/Events.aspx

Briefly, the take away from the article - Events are encapsulation over delegates. 简而言之,本文的主要内容-事件是对委托的封装。

Quote from article: 引用文章:

Suppose events didn't exist as a concept in C#/.NET. 假设事件在C#/。NET中不存在。 How would another class subscribe to an event? 另一个班级将如何订阅事件? Three options: 三种选择:

  1. A public delegate variable 公共委托变量

  2. A delegate variable backed by a property 由属性支持的委托变量

  3. A delegate variable with AddXXXHandler and RemoveXXXHandler methods 具有AddXXXHandler和RemoveXXXHandler方法的委托变量

Option 1 is clearly horrible, for all the normal reasons we abhor public variables. 选项1显然很可怕,出于所有正常原因,我们都讨厌公共变量。

Option 2 is slightly better, but allows subscribers to effectively override each other - it would be all too easy to write someInstance.MyEvent = eventHandler; 选项2稍好一些,但允许订阅者有效地彼此覆盖-编写someInstance.MyEvent = eventHandler太容易了。 which would replace any existing event handlers rather than adding a new one. 这将替换任何现有的事件处理程序,而不是添加一个新的事件处理程序。 In addition, you still need to write the properties. 此外,您仍然需要编写属性。

Option 3 is basically what events give you, but with a guaranteed convention (generated by the compiler and backed by extra flags in the IL) and a "free" implementation if you're happy with the semantics that field-like events give you. 选项3基本上是事件为您提供的内容,但是如果您对类似字段的事件给您带来的语义感到满意,则可以使用保证的约定(由编译器生成并由IL中的额外标志提供支持)和“免费”实现。 Subscribing to and unsubscribing from events is encapsulated without allowing arbitrary access to the list of event handlers, and languages can make things simpler by providing syntax for both declaration and subscription. 订阅事件和取消订阅事件是封装在一起的,不允许任意访问事件处理程序列表,并且语言可以通过提供声明和订阅的语法来简化事情。


#3楼

To understand the differences you can look at this 2 examples 要了解差异,您可以查看以下两个示例

Example with Delegates (in this case, an Action - that is a kind of delegate that doesn't return a value) 委托示例(在这种情况下,是一个Action-这是一种不返回值的委托)

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

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

To use the delegate, you should do something like this: 要使用委托,您应该执行以下操作:

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

This code works well but you could have some weak spots. 这段代码效果很好,但是您可能会遇到一些薄弱环节。

For example, if I write this: 例如,如果我这样写:

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

with the last line of code, I have overridden the previous behaviors just with one missing + (I have used = instead of += ) 在最后一行代码中,我只用了一个+覆盖以前的行为(我用=代替+=

Another weak spot is that every class which uses your Animal class can raise RaiseEvent just calling it animal.RaiseEvent() . 另一个弱点是,每个使用Animal类的类都可以仅将其animal.RaiseEvent()来引发RaiseEvent

To avoid these weak spots you can use events in c#. 为了避免这些弱点,您可以在c#中使用events

Your Animal class will change in this way: 您的动物类将以这种方式更改:

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"));
    }
}

to call events 呼叫事件

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

Differences: 差异:

  1. You aren't using a public property but a public field (using events, the compiler protects your fields from unwanted access) 您不是在使用公共属性,而是在使用公共字段(使用事件,编译器可以保护您的字段免受不必要的访问)
  2. 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. 在这种情况下,它不会引起我先前显示的覆盖该行为的错误。
  3. No one outside of your class can raise the event. 班上没有人可以发起活动。
  4. Events can be included in an interface declaration, whereas a field cannot 事件可以包含在接口声明中,而字段不能

Notes: 笔记:

EventHandler is declared as the following delegate: EventHandler被声明为以下委托:

public delegate void EventHandler (object sender, EventArgs e)

it takes a sender (of Object type) and event arguments. 它需要一个(对象类型的)发送者和事件参数。 The sender is null if it comes from static methods. 如果发件人来自静态方法,则它为null。

This example, which uses EventHandler<ArgsSpecial> , can also be written using EventHandler instead. 此示例使用EventHandler<ArgsSpecial> ,也可以改用EventHandler编写。

Refer here for documentation about EventHandler 请参阅此处以获取有关EventHandler的文档


#4楼

What a great misunderstanding between events and delegates!!! 活动与代表之间的巨大误解!!! A delegate specifies a TYPE (such as a class , or an interface does), whereas an event is just a kind of MEMBER (such as fields, properties, etc). 委托指定TYPE(例如, classinterface ),而事件只是一种MEMBER(例如,字段,属性等)。 And, just like any other kind of member an event also has a type. 而且,就像其他任何类型的成员一样,事件也具有类型。 Yet, in the case of an event, the type of the event must be specified by a delegate. 但是,对于事件,事件类型必须由委托人指定。 For instance, you CANNOT declare an event of a type defined by an interface. 例如,您不能声明接口定义的类型的事件。

Concluding, we can make the following Observation: the type of an event MUST be defined by a delegate . 最后,我们可以进行以下观察:事件的类型必须由委托定义 This is the main relation between an event and a delegate and is described in the section II.18 Defining events of ECMA-335 (CLI) Partitions I to VI : 这是事件和委托之间的主要关系,在II.18节“ 定义 ECMA-335(CLI)分区I至VI的 事件 ”中进行了描述:

In typical usage, the TypeSpec (if present) identifies a delegate whose signature matches the arguments passed to the event's fire method. 在典型用法中,TypeSpec(如果存在)会标识其签名与传递给事件的fire方法的参数匹配的委托

However, this fact does NOT imply that an event uses a backing delegate field . 但是, 此事实并不意味着事件使用后备委托字段 In truth, an event may use a backing field of any different data structure type of your choice. 实际上,事件可以使用您选择的任何其他数据结构类型的支持字段。 If you implement an event explicitly in C#, you are free to choose the way you store the event handlers (note that event handlers are instances of the type of the event , which in turn is mandatorily a delegate type ---from the previous Observation ). 如果您在C#中显式实现一个事件,则可以自由选择存储事件处理程序的方式 (请注意, 事件处理程序该事件类型的实例,而从先前的观察中 ,该类型又是强制类型委托类型) )。 But, you can store those event handlers (which are delegate instances) in a data structure such as a List or a Dictionary or any other else, or even in a backing delegate field. 但是,您可以将这些事件处理程序(它们是委托实例)存储在诸如ListDictionary或其他任何数据结构的数据结构中,甚至存储在支持的委托字段中。 But don't forget that it is NOT mandatory that you use a delegate field. 但是请不要忘记使用委托字段不是强制性的。


#5楼

An Event declaration adds a layer of abstraction and protection on the delegate instance. 事件声明在委托实例上添加了一层抽象和保护。 This protection prevents clients of the delegate from resetting the delegate and its invocation list and only allows adding or removing targets from the invocation list. 此保护可防止委托的客户端重置委托及其调用列表,并且仅允许在调用列表中添加或删除目标。


#6楼

In addition to the syntactic and operational properties, there's also a semantical difference. 除了语法和操作属性外,还存在语义上的差异。

Delegates are, conceptually, function templates; 从概念上讲,代表是功能模板。 that is, they express a contract a function must adhere to in order to be considered of the "type" of the delegate. 也就是说,他们表示必须履行职能的合同,才能被视为代表的“类型”。

Events represent ... well, events. 事件代表……嗯,事件。 They are intended to alert someone when something happens and yes, they adhere to a delegate definition but they're not the same thing. 它们旨在在某事发生时向某人发出警报,是的,他们遵循委托定义,但并非同一个人。

Even if they were exactly the same thing (syntactically and in the IL code) there will still remain the semantical difference. 即使它们是完全相同的东西(在语法上和IL代码中),仍将保留语义上的差异。 In general I prefer to have two different names for two different concepts, even if they are implemented in the same way (which doesn't mean I like to have the same code twice). 通常,我喜欢为两个不同的概念使用两个不同的名称,即使它们以相同的方式实现(这并不意味着我希望两次拥有相同的代码)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值