What does the event keyword really do? - c#

public delegate void SecondChangedHandler(
object clock,
TimeInfoEventArgs timeInformation);
public event SecondChangedHandler SecondChanged;
I have written a clock based on this article.
Now if i remove the event keyword i get the same result, so what does event really do?

It's compiled differently. It makes it so someone can't do
mySecondChangedHandler.SecondChanged = SomeMethod(...); //overwrite
mySecondChangedHandler.SecondChanged(...); //invoke
but only
mySecondChangedHandler.SecondChanged += SomeMethod(...);
mySecondChangedHandler.SecondChanged -= SomeMethod(...);

The event keyword creates a private delegate field, and a pair of public event accessors called add_EventName and remove_EventName. (details)
This means that writing EventName inside the class returns the delegate instance, allowing you to call or inspect the event handlers.
Outside the class, EventName doesn't really exist; all you can do is write EventName += something and EventName -= something, and the compiler will convert it into calls to the accessors. (like a property)
For more details, see this series of blog posts.

The event keyword does two things
It supplied permissions. Only the class can raise the event, however any external method can invoke the raw delegate
It provides metadata which can be used for designers and the like

The event keywords means only methods on the instance that hosts the SecondChanged field can invoke it. External attempts will fail.

The event keyword creates a pair of accessors for a delegate. These are effectively two methods (add and remove) that are called when you subscribe or unsubscribe from the event.
In your case, you're creating a "field-like event". The compiler makes a delegate behind the scenes, and allows you to subscribe and unsubscribe from it's invocation list. This means that you have all of the functionality of a delegate, but you're restricting access so that that outside world can "handle" the event, but not raise the event (invoke the delegate).
You can, however, also explicitly create your own accessors for an event, and these can do other things (though that's not typically recommended unless there is a good reason to do so).

Quote from C# lang reference about keyword event,
Events are a special kind of multicast delegate that can only be invoked from within the class or struct where they are declared (the publisher class).

Related

Does subscribing to an event add the handler function to the event or the event delegate's invocation list?

I am trying to debunk how many tutorials on .NET Events and Delegates are using the Event and the Delegate (believe this is an invocation list?) interchangeably when describing an object subscribing to the event.
In the case of this example code, some I've listened to have said that handlerFunction is being added to the Event's invocation list, whilst others say it is being added to to the delegate (which is what I originally thought was the (only) invocation list.)
What is the breakdown of where the subscribers are actually subscribing to?
delegate void MyEventHandler (int x, string y);
class myClass {
public event MyEventHandler MyEvent;
}
myClass obj = new myClass();
obj.MyEvent += handlerFunction;
Defining an event creates a variable with the delegate as the type. It refers to an instance of the delegate. So you could say that the event has an invocation list or that the instance of the delegate has an invocation list, because event = instance of delegate.
This is why if you declare an event, as you have:
public event MyEventHandler MyEvent;
MyEvent is a Delegate, and you can call its GetInvocationList() method. GetInvocationList() is a member of Delegate.
Delegates are immutable, not mutable. So technically when you subscribe an additional handler to an event you're not adding a handler to an existing delegate instance's invocation list, you're creating a new delegate whose invocation list will contain everything in the old delegate's invocation list plus your new handler, and assigning that new delegate to the backing store for that event.
All that said, I expect that what you're reading is just shortcutting a bit and not going into overly specific details here as it's not really a point relevant to what I expect they're actually trying to discuss at the moment.
As for the difference between thinking of it as "a delegate" versus, "an invocation list". Every delegate is just an invocation list. There isn't anything more to any delegates. There really isn't anything particularly wrong with referring to either here. Technically the event has a delegate, and subscribing the event handler is creating a new delegate that has a slightly different invocation list internally than the old delegate, and that new delegate is being assigned to the backing store. Shortcutting that to saying that adding a handler is adding a new method to the invocation list is...at least getting across the important points there. That the invocation list is held in a delegate instance isn't really particularly critical to understanding how to subscribe a handler to an event.

Remove event listener from local variable

Do I have to worry about removing event listeners assigned to local variables?
Consider the following sample:
var zipUtil = new ZipUtil();
zipUtil.ProgressChanged += ZipUtil_ProgressChanged;
I'm creating an instance of the ZipUtil class which is stored as a local variable within a method. Do I have to remove the listener (zipUtil.ProgressChanged -= ZipUtil_ProgressChanged;) before the method terminates or is it okay to skip the step?
No, you don't have to remove that event handling method.
When adding an event handler to an event, a reference from the (object containing the) event to the event handler is created, not the other way round. Once zipUtil goes out of scope, the event handler will not make any difference pertaining to references to zipUtil.
Two lines of code are never enough to make the call accurately. But it is very unlikely you'll need to unsubscribe explicitly. There are two possible problem scenarios:
the class may fire its event at an inopportune time, after your object is disposed for example. That's fairly unlikely in this scenario, surely the ZipUtil class stops raising ProgressChanged events when you stop calling its methods. Not completely out of the question, it could do work on a background thread for example. Not visible from your snippet.
you can have a garbage collection problem due to events. The event delegate keeps an implicit reference to your class object, necessary so it can call ZipUtil_ProgressChanged() method. If it is an instance method, not clear from your snippet. That reference will keep your outer class alive. But not the other way around. Given that the lifetime of the ZipUtil object is restricted to the method and you surely want your outer class to survive at least to the end of the method, this should never be a problem.
High odds that ZipUtil implements IDisposable btw. Do make sure you use the using statement if it does.

c# Using a reference to an event member

Anybody know why this is not possible?
If the event is just a MulticastDelegate instance you should be able to reference it in the code. the compiler says EventA can only be on left side of -= or +=.
public delegate void MyDelegate();
public event MyDelegate EventA;
public void addHandlerToEvent(MulticastDelegate md,Delegate d){
md+=d;
}
///
addHandlerToEvent(EventA,new MyDelegate(delegate(){}));
An event is not a multicast delegate, just like a property is not a field.
C#'s event syntax wraps multicast delegates to make life easier by providing syntactic sugar for adding and removing handler delegates. Your event definition would be compiled to the following:
private MyDelegate _EventA;
public event MyDelegate EventA
{
[MethodImpl(MethodImplOptions.Synchronized)]
add
{
_EventA = (MyDelegate)Delegate.Combine(_EventA, value);
}
[MethodImpl(MethodImplOptions.Synchronized)]
remove
{
_EventA = (MyDelegate)Delegate.Remove(_EventA, value);
}
}
The add and remove methods within the expanded event definition are then called when you use operator += and operator -= on the event.
This is done in order to hide the internals of the multicast delegate, but expose a simple way to implement publishing/subscribing to events. Being able to get the underlying delegate (outside of the class where it's defined) would break that intentional encapsulation.
An event is a member which binds a pair of add/remove methods(*), each of which accepts a delegate corresponding to the event signature. By default, the C# compiler will for each event auto-define a MultiCast delegate field along with add and remove members which will take the passed-in delegate and add or remove them to/from that MulticastDelegate field. The statement myEvent += someMethod;, when performed outside the class defining the event, is the required syntactic shorthand for, essentially myEvent.AddHandler(someMethod), and myEvent -= someMethod; for myEvent.RemoveHandler(someMethod), except that there is no way in C# to call the add/remove methods except using the += and -= notation.
Things are a little tricky when using the += and -= notation within the class which defines an event, since the field defined by the auto-generated event code has the same name as the event, and the behavior of myEvent += someMethod; will vary with different versions of C#.
(*) Technically a trio, since an event also includes a 'raise' method, but in practice that method is essentially never used.
Events are backed by multicast delegates, yes, but their purpose is to provide an implementation of the observer pattern, where observers (delegates in this case) may only be registered (+=) or unregistered (-=). If normal access to the backing delegate were possible outside the class itself, then it would be possible for client code to interfere with an unrelated delegate that was registered elsewhere, which could mess things up. It's also somewhat beside the point of the observer pattern to look at which other things are observing the event in question.
If you need to perform this kind of manipulation of the backing delegate, it must be done within the class (where it's treated as a regular delegate rather than an event).
You can also implement the backing delegate explicitly and provide an accessor to register/unregister with it:
private EventHandler SomeEvent;
public event EventHandler
{
add
{
SomeEvent += value;
}
remove
{
SomeEvent -= value;
}
}
This way you can provide direct access to the delegate if you need to. It's still best to provide public access to it for the purposes of subscribing/unsubscribing as an event though (rather than a raw delegate), otherwise you can run into thread-safety problems with data races on the delegates.

Firing an event in C# with no attatched delegate methods?

I've just encountered a bug in the program I'm writing where an exception was thrown stating an "object reference must be set to an instance of an object". Upon investigation, I found that this exception was thrown when trying to fire an event BUT the event didn't have any delegate methods added to it.
I wanted to check that my understanding was correct that as a developer you shouldn't fire events without first checking that the event doesn't equal null? For example:
if (this.MyEventThatIWantToFire != null)
{
this.MyEventThatIWantToFire();
}
Thanks in advance for the advice/thoughts.
The pattern you've shown is broken in a multi-threaded environment. MyEventThatIWantToFire could become null after the test but before the invocation. Here's a safer approach:
EventHandler handler = MyEventThatIWantToFire;
if (handler != null)
{
handler(...);
}
Note that unless you use some sort of memory barrier, there's no guarantee you'll see the latest set of subscribers, even ignoring the obvious race condition.
But yes, unless you know that it will be non-null, you need to perform a check or use a helper method to do the check for you.
One way of making sure there's always a subscriber is to add a no-op subscriber yourself, e.g.
public event EventHandler MyEventThatIWantToFire = delegate {};
Of course, events don't have to be implemented with simple delegate fields. For example, you could have an event backed by a List<EventHandler> instead, using an empty list to start with. That would be quite unusual though.
An event itself is never null, because the event itself is just a pair of methods (add/remove). See my article about events and delegates for more details.
You shouldn't do it that way - if someone where to remove a listener between the if and the call to the event, you'd get an exception. It is good practise to use it with a local variable:
protected void RaiseEvent()
{
var handler = Event;
if(handler != null)
handler(this, EventArgs.Empty);
}
Of course, this has the disadvantage of maybe calling a listener that already was removed between the creation of the local variable and the call to the handler.
Yes, you should check it for null but the way you're doing it leads to a race condition. It's possible the event may end up being null anyway if someone unsubscribes the last delegate in between your "if" and your event raise. The accepted way to do this is like:
var temp = this.MyEventThatIWantToFire;
if (temp != null) {
this.temp(this, EventArgs.Empty);
}
or alternatively, ensure there's always at least one delegate in the invocation list by declaring your event like this:
public event EventHandler MyEventThatIWantToFire = delegate {};
Make sense?
Yes, your understanding is correct. It's up to you to check the delegate's value before calling it.
Most delegates - which events are - are "multi-cast" delegates. This means that a delegate can manage a list of one or more methods that it will call when activated.
When the delegate evaluates to a null value, there are no registered methods; therefore, there is nothing to call. If it evaluates to something other than a null value, there is at least one method registered. Calling the delegate is an instruction to call all methods it has registered. The methods are called in no guaranteed order.
Using the addition-assignment operator (+=) or addition operator (+) adds a method to the delegate's list of methods. Using the subtraction-assignment operator (-=) or subtraction operator (-) removes a method from the delegate's list of methods.
Also note that the called methods are executed from the caller's thread. This is important if you are using events to update your user interface controls. In this situation, use of your control's InvokeRequired property lets you handle cross-threading calls (using Invoke() or BeginInvoke()) gracefully.
Yes in C# if an event has no delegates, it will be null, so you must check
Yes, you must check whether event is not null. Mostly you encounter protected method that does the check and invokes event, or even constructs event args. Something like this:
public event EventHandler Foo;
protected void OnFoo() {
if (Foo == null)
return;
Foo(this, new EventArgs());
}
This approach also alows your derived classes to invoke (or prevent invoking) the event.

How can I retrieve all methods of an event?

I have an event Load
public delegate void OnLoad(int i);
public event OnLoad Load;
I subscribe to it with a method:
public void Go()
{
Load += (x) => { };
}
Is it possible to retrieve this method using reflection? How?
In this particular case you could, with reflection. However, in general, you can't. Events encapsulate the idea of subscribers subscribing and unsubscribing - and that's all. A subscriber isn't meant to find out what other subscribers there are.
A field-like event as you've just shown is simply backed by a field of the relevant delegate type, with autogenerated add/remove handlers which just use the field. However, there's nothing to say they have to be implemented like that. For example, an event can store its subscribers in an EventHandlerList, which is efficient if you have several events in a class and only a few of them are likely to be subscribed to.
Now I suppose you could try to find the body of the "add" handler, decompile it and work out how the event handlers are being stored, and fetch them that way... but please don't. You're creating a lot of work, just to break encapsulation. Just redesign your code so that you don't need to do this.
EDIT: I've been assuming that you're talking about getting the subscribers from outside the class declaring the event. If you're inside the class declaring the event, then it's easy, because you know how the event is being stored.
At that point, the problem goes from "fetching the subscribers of an event" to "fetching the individual delegates making up a multicast delegate" - and that's easy. As others have said, you can call Delegate.GetInvocationList to get an array of delegates... and then use the Delegate.Method property to get the method that that particular delegate targets.
Now, let's look again at your subscription code:
public void Go()
{
Load += (x) => { };
}
The method that's used to create the delegate here isn't Go... it's a method created by the C# compiler. It will have an "unspeakable name" (usually with angle brackets) so will look something like this:
[CompilerGenerated]
private static void <Go>b__0(int x)
{
}
Now, is that actually what you want to retrieve? Or were you really looking to find out which method performed the subscription, rather than which method was used as the subscribed handler?
If you call Load.GetInvocationList() you will be handed back an array of Delegate types. From the these types, you can access the MethodInfo.
You could use the GetInvocationList method which will give you all the subscribers.

Categories