Difference in invoking through Delegates and Event

2019-02-18 10:32发布

问题:

What is the difference?

Using Delegate

public delegate void TestDelegate();
public TestDelegate delObj = SomeMethod;

public void SomeMethod()
{
    .....
}

public void Test()
{
    if(delObj != null)
        delObj();
}

Using Event

public delegate void TestDelegate();
public event TestDelegate EdelObj += SomeMethod;

public void SomeMethod()
{
    .....
}

public void Test()
{
    if(EdelObj != null)
        EdelObj();
}

Both seem to work. Can anybody explain what is the difference and which scenario should we use one of the above?

Edit Chaining works for both. Sorry it was a mistake from my end.

Thanks Nishant

回答1:

An event declaration is really just a special kind of property that's used to expose a delegate. Instead of get and set accessors, though, it creates add and remove ones. Normally they're implemented automatically, but if you desire you can add custom behavior:

private MyEventHandler handler;
public event MyEventHandler MyEvent {
    add {
        handler += value;
        Trace.WriteLine("MyEvent handler attached.");
    }
    remove {
        handler -= value;
        Trace.WriteLine("MyEvent handler removed.");
    }
}

This does two things. First, since events are properties they can be included in interfaces. Second, since MyEvent does not return a value, the delegate is completely encapsulated and only the object that owns it can invoke it. Other ways of exposing delegates result in a delegate that can be invoked by just about anyone.

Beyond that bit of special language support, the other major difference between events and delegates is a convention rather than a language or framework feature: Events are expected to follow certain patterns, such as making sure that the delegate on which the event is based follows the pattern established by the EventHandler delegate.

Generally, events are preferred whenever the semantics are that of an object notifying anyone who's interested about a change in its stage. Delegates are preferred in situations where you want others to be able to define behavior by supplying their own procedure, such as the delegate parameters that are taken by many of the extension methods on IEnumerable that are used in LINQ.



回答2:

It works exactly same. If you use

public event EventHandler SomeEvent;

the C# compiler does (simplified code):

private EventHandler SomeEventField;
public void add_SomeEvent( EventHandler handler) {
    this.SomeEventField = (EventHandler)Delegate.Combine(this.SomeEvent, handler);
}
public void remove_SomeEvent( EventHandler ) {
   this.SomeEventField = (EventHandler)Delegate.Remove(this.SomeEvent, handler);
}

The method add_SomeEvent is called when you use SomeEvent += ... and the remove_SomeEvent is called when you use SomeEvent -= ....

However in both cases there are used same delegates.



回答3:

It is not delegate vs event, an event is a kind-of property around a delegate.

In general you should always use the second scenario because in the first public TestDelegate delObj is a public field, breaking Encapsulation.

You use events in the interface of a class, delegates as parameters to methods.



回答4:

It's effectively a property wrapper around the event.

The main difference is that you can't invoke/raise the event from outside the class, whereas you can invoke the public delegate.

Chaining (+=) is no different for delegates and events.



回答5:

C# has a lot of constructs that don't add anything new to the language, but are simply syntactic sugar for a construct, because the construct requires some pattern of code which is tiresome to type every time over and over again. For example the using statement is equivalent of a try-finally block with a call to the dispose method, and properties are just syntactic sugar for an get and/or set method.

In a similar way events are just syntactic sugar for a delegate field. There are some subtle differences however, which others have mentioned. Since a public field isn't recommended, the delegate would have to be encapsulated and a nice way of doing that is with an event. And (as Mark mentions) the event is only invokable from inside of the class.

I usually choose between delegate field and event based on what I conceptually think the field or event should represent. If it represents something anyone would want to be notified of, I'd recommend the event. Otherwise if it represents for example a function to acquire a result, I'd use a delegate field.