What are the differences between delegates and eve

2019-01-01 02:44发布

What are the differences between delegates and an events? Don't both hold references to functions that can be executed?

10条回答
皆成旧梦
2楼-- · 2019-01-01 03:12

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.

查看更多
路过你的时光
3楼-- · 2019-01-01 03:16

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). 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:

In typical usage, the TypeSpec (if present) identifies a delegate whose signature matches the arguments passed to the event’s fire method.

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). 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. But don’t forget that it is NOT mandatory that you use a delegate field.

查看更多
情到深处是孤独
4楼-- · 2019-01-01 03:19

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. 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).

查看更多
高级女魔头
5楼-- · 2019-01-01 03:19

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)

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().

To avoid these weak spots you can use events in c#.

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:

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.

This example, which uses EventHandler<ArgsSpecial>, can also be written using EventHandler instead.

Refer here for documentation about EventHandler

查看更多
墨雨无痕
6楼-- · 2019-01-01 03:23

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.

查看更多
忆尘夕之涩
7楼-- · 2019-01-01 03:24

Covariance and Contravariance provide extra flexibility to the delegate objects. On the other hand, an event has no such concepts.

  • Covariance allows you to assign a method to the delegate where the return type of the method is a class which is derived from the class that specifies the return type of the delegate.
  • Contravariance allows you to assign a method to the delegate where the parameter type of the method is a base class of the class that is specified as the parameter of the delegate.
查看更多
登录 后发表回答