I have a basic doubt. Internally how are events represented as methods or as (fields)objects. If event is a field then how one can still contain events in the interface definition.
Thanks
JeeZ
If you type this:
public event EventHandler MyEvent;
what the compiler generates is (simplified) this:
// declares a normal delegate of type 'EventHandler'
private EventHandler _myEvent;
// declares 'add_MyEvent' and 'remove_MyEvent' methods similar to a property
public event EventHandler MyEvent {
add { _myEvent += value; }
remove { _myEvent -= value; }
}
An event is similar to a property; a wrapper around a delegate that only allows methods to be added or removed. This is so you can't completely re-assign the delegate and delete other people's subscriptions to it.
All you are doing when specifying an event in an interface is that any implementing classes should have the add and remove methods for the event. Very similar to declaring a property on an interface, in fact.
This is also why you can only call or re-assign the event in the class it is declared in - any references to the MyEvent event within the class are re-routed to use the delegate directly, whereas outside the class you can only access the add and remove methods, not the delegate directly.
#thecoop's answer is a very good description of "field-like events" (noting the "simplified" caveat) - but note that actually events can be implemented any way you like. All the event defines is an add/remove accessor pair (which is why it can be defined on the interface, like a property).
For example, with sparce events the following may be common:
private static readonly object FooKey = new object(), BarKey = new object();
public event EventHandler Foo {
add {Events.AddHandler(FooKey, value);}
remove {Events.RemoveHandler(FooKey, value);}
}
public event MouseClickEventHandler Bar {
add {Events.AddHandler(BarKey, value);}
remove {Events.RemoveHandler(BarKey, value);}
}
where Events is an EventHandlerList, usually delay-loaded:
private EventHandlerList events;
protected EventHandlerList Events {
get {
if(events == null) events = new EventHandlerList();
return events;
}
}
Or you could do anything else you like. Within reason (noting the expected behaviour of event subscriptions and delegate equality / composite delegates).
Events are not represented as fields nor methods. They are simply events, as far as the meta-data for a class is concerned.
Similarly properties have a special flag (although these get stored as methods with well known names).
Related
Is there anything wrong with subscribing to event with
MyPopup.CustomPopupPlacementCallback = popupFixCentered;
instead of:
MyPopup.CustomPopupPlacementCallback += popupFixCentered;
For example, if I am changing to different callback from another method I want to make sure I have only one callback subscribed without needing to -= the correct one.
Well, it sounds like you didn't try it. If you did, you would get the following compilation error:
The event 'XXX' can only appear on the left hand side of += or -= (except when used from within the type 'YourClass')
The error is pretty clear: you can only use the += and -= operators on the event.
If you try to assign to the event from within the class that defines the event, then it will "work". But the reason it appears to be able to assign to an event in that case is because it's actually not accessing the event. It's accessing an auto-generated private delegate instance that you may not realize is actually there.
Quoting from Chris Burrows' article on the subject:
outside of the class or struct that defines a field-like event E, binding to the name E resolves to the event itself, on which the only legal operation is calling an accessor; inside the class or struct that defines a field-like event E, binding to the name E resolves to the private delegate field.
To understand this, you need to visualize that when you define an event such as:
public event EventHandler MyEvent;
... what you don't see, is that it actually gets translated into something like this (I'm copying this from Jon Skeet's article on events and delegates. Also note that the exact code it gets translated into has changed between versions of C#, so it may be a bit different, but the general idea is the same):
private EventHandler _myEvent;
public event EventHandler MyEvent
{
add
{
lock (this)
{
_myEvent += value;
}
}
remove
{
lock (this)
{
_myEvent -= value;
}
}
}
So when you access MyEvent from outside the class, you can only invoke the add and remove methods through the += and -= operators.
But from within the class, accessing MyEvent means something different. It actually becomes a reference to that private _myEvent delegate variable that you can't see, but it is there. Because this is a delegate type, then you can use the assignment (=) operator on it.
So, to achieve what you want, you could define a public method in the same class that defines the event, and use that method to set your new event handler.
Something like this:
public class MyClass
{
public event EventHandler MyEvent;
public void setSingleEventHandler(EventHandler eventHandler)
{
this.MyEvent = eventHandler;
}
}
But if you are going to do that, then it defeats the purpose of the event type. If you only want to invoke a single event handler at most at any given time, then defining it this way (without using the event keyword) makes more sense:
public class MyClass
{
public EventHandler MyEvent { get; set; }
}
References
Jon Skeet article: Delegates and Events
Chris Burrows article: (also check out the rest of the series): Events get a little overhaul in C# 4, Part II: Semantic Changes and +=/-=
I just tested it. Yes, you can use the = operator to assign to an event. (Edit: Apparently only from within the same class)
delegate void Foo();
event Foo bar;
Method()
{
bar = () => { Console.WriteLine("1"); };
bar();
bar = () => { Console.WriteLine("2"); };
bar();
}
Produces the output:
1
2
But if you try to assign from outside the class, it will give you an error.
You can get around this by using a java-style set method:
SetBar(Foo foo)
{
bar = foo;
}
Only time I'd ever recommend java convention for external access of properties :)
The following is an example from MSN website. This is a good example, I just do not understand what this line:
EventHandler<CustomEventArgs> handler = RaiseCustomEvent;
is doing?
Is not RaiseCustomEvent an event based on the definition at the top of the program?
Why is an Event is equated to an EventHandler? These are two different types.
Where is RaiseCustomEvent being initialized? If it is not initialized how can we copy it or why do we want to copy something uninitialized to something else?
What is the handler variable there for? Is that an event or an event handler?
I'm very confused and am trying hard to get this event/event handler/delegate issue understood.
Here is the sample code from MSN
namespace DotNetEvents
{
using System;
using System.Collections.Generic;
// Define a class to hold custom event info
public class CustomEventArgs : EventArgs
{
public CustomEventArgs(string s)
{
message = s;
}
private string message;
public string Message
{
get { return message; }
set { message = value; }
}
}
// Class that publishes an event
class Publisher
{
// Declare the event using EventHandler<T>
public event EventHandler<CustomEventArgs> RaiseCustomEvent;
public void DoSomething()
{
// Write some code that does something useful here
// then raise the event. You can also raise an event
// before you execute a block of code.
OnRaiseCustomEvent(new CustomEventArgs("Did something"));
}
// Wrap event invocations inside a protected virtual method
// to allow derived classes to override the event invocation behavior
protected virtual void OnRaiseCustomEvent(CustomEventArgs e)
{
// Make a temporary copy of the event to avoid possibility of
// a race condition if the last subscriber unsubscribes
// immediately after the null check and before the event is raised.
EventHandler<CustomEventArgs> handler = RaiseCustomEvent;
// Event will be null if there are no subscribers
if (handler != null)
{
// Format the string to send inside the CustomEventArgs parameter
e.Message += String.Format(" at {0}", DateTime.Now.ToString());
// Use the () operator to raise the event.
handler(this, e);
}
}
}
//Class that subscribes to an event
class Subscriber
{
private string id;
public Subscriber(string ID, Publisher pub)
{
id = ID;
// Subscribe to the event using C# 2.0 syntax
pub.RaiseCustomEvent += HandleCustomEvent;
}
// Define what actions to take when the event is raised.
void HandleCustomEvent(object sender, CustomEventArgs e)
{
Console.WriteLine(id + " received this message: {0}", e.Message);
}
}
class Program
{
static void Main(string[] args)
{
Publisher pub = new Publisher();
Subscriber sub1 = new Subscriber("sub1", pub);
Subscriber sub2 = new Subscriber("sub2", pub);
// Call the method that raises the event.
pub.DoSomething();
// Keep the console window open
Console.WriteLine("Press Enter to close this window.");
Console.ReadLine();
}
}
}
An event is to a delegate type what a property is to any other type.
If you have a property such as this:
public string Name {get;set;}
Obviously you can do something like this:
string name = Name;
The property has an underlying string value that is accessed/modified by the property.
Similarly, an event has a delegate under the hood, and that delegate is of the type defined in the event declaration. That it's an event simply defines how handlers of that event are added/removed from that underlying delegate.
From within the declaring type (that's a key point; you can't do this externally) you can access that underlying delegate in order to invoke it. That's the reason for doing the code that you see; they're accessing the underlying delegate so that they can verify that it has some handlers within it, and if so, it invokes them.
So, to answer the questions explicitly:
Is not RaiseCustomEvent an event based on the definition at the top of the program?
RaiseCustomEvent is the type of the underlying delegate that the event wraps.
Why is an Event is equated to an EventHandler? These are two different types.
It's not strictly equality. It's pulling out the underlying delegate from within the event.
Where is RaiseCustomEvent being initialized? If it is not initialized how can we copy it or why do we want to copy something uninitialized to something else?
In this case it's using the automatic add/remove implementations that the framework will provide, rather than manually defining them. The automatically defined add handler will initialize the underlying delegate if it is currently null. If the event declaration would
define a custom add handler, it would need to handle that case.
What is the handler variable there for? Is that an event or an event handler?
It is a single delegate that represents the combination of all of the event handlers. Within it's definition will be an invocation list of all of the individual methods that make up that delegate. So it's not a single event handler, it's the collection of all of them. Since it's pulled out of the event it no longer strictly represents that event; it's a copy of what was in the event at some point in the past. You cannot change the event (i.e. add a new handler) using the delegate that you've pulled out of it.
I'll try the four questions you pose:
1) Is not RaiseCustomEvent an event based on the definition at the top of the program ?
The CustomEventArgs class holds some data (arguments) for the event we want to declare. It is used as type parameter in the type EventHandler<CustomEventArgs>. This last type is a delegate type, which means it represents one or more methods of the same signature and return type. (Zero methods will be a null reference as the value of the delegate.)
The type of the event RaiseCustomEvent is that delegate type, EventHandler<CustomEventArgs>.
2) Why an Event is equated to an EventHandler? These are two diffeent types
An event consists on a pair of special methods, accessors, one add accessor and one remove accessor. Both have one parameter of the same type which is called the type of the event. That type must be a delegate type. In this case that type is EventHandler<CustomEventArgs>.
In this example the event is a so-called field-like event. It generates a backing field of the same type, EventHandler<CustomEventArgs>, the delegate type. That field has the same name as the event itself!
When they do:
// Make a temporary copy of the event to avoid possibility of
// a race condition if the last subscriber unsubscribes
// immediately after the null check and before the event is raised.
EventHandler<CustomEventArgs> handler = RaiseCustomEvent;
they copy the current value of that backing field into the local variable handler. The comment describes why. They want to check for null before they invoke the delegate.
3) Where is RaiseCustomEvent have been initialized? If not initialized how can we copy or why do we want to copy something uninitialized to soemthig else.
It usually gets initialized when people use the add accessor of the event. This takes place through the special C# syntax +=. This is called subscribing to the event. See the Subscriber class.
Actually pub.RaiseCustomEvent += HandleCustomEvent; translates to pub.add_RaiseCustomEvent(HandleCustomEvent);, so it is a call to the add accessor. The add accessor is generated by the compiler (in a field-like event), and it initializes the backing field.
4)I do not know what is handler variable? is that an event or an event handler ?
It is a delegate. It is not an event. It is a copy of the backing field of the field-like event at one moment in time.
I have been looking in to subscribing to an event using a weak event pattern. With the .NET 4.5 framework, we have a slick looking WeakEventManager class. Weakly subscribing to an event is as simple as
WeakEventManager<EventSource, SomeEventEventArgs>.AddHandler(source, "SomeEvent", source_SomeEvent);
I'm not a big fan of 'stringly-typed' code however. I have been trying to find a way around using the string name of the event to subscribe to. The only way I have found to obtain the name of the event is using a lambda expression in the class that defines the event. In my scenario, I own the class defining the event so I can change it however I like. I have been trying to find a clean way to subscribe and unsubscribe to my event and here is what I disliked the least.
public event EventHandler<EventArgs> LoggingOn;
public event EventHandler<EventArgs> LoggingOn_Weak
{
add
{
var eventName = this.GetEventName(() => this.LoggingOn);
WeakEventManager<CurrentUser, EventArgs>.AddHandler(this, eventName, value);
}
remove
{
var eventName = this.GetEventName(() => this.LoggingOn);
WeakEventManager<CurrentUser, EventArgs>.RemoveHandler(this, eventName, value);
}
}
// In a base class view model in my scenario
private string GetEventName<T>(System.Linq.Expressions.Expression<Func<T>> expression)
{
return (expression.Body as System.Linq.Expressions.MemberExpression).Member.Name;
}
protected void OnLoggingOn(object sender, EventArgs e)
{
var handler = this.LoggingOn;
if (handler != null)
{
handler(sender, e);
}
}
Using custom event accessors I was able to avoid clunky (in my opinion) methods like LoggingOn_Subscribe(EventHandler) or adding name properties for each event. Unfortunately it is not so intuitive in that people subscribing to the event are doing so in the classic manner but have no idea other than the "_Weak" part of the name that indicates it is being subscribed to weakly.
As for my questions..
1) I have never used weak events or custom event accessors before. The code above appears to work, however, I would just like to make sure there is nothing technically wrong with it. Is there anything I'm doing here to shoot myself in the foot?
2) From a design perspective, is this a terrible idea? Are there any major design concerns I should consider? Is there better alternative? Should i just suck it up and subscribe from my subscriber using a stringly-typed event name?
Thoughts?
With .NET 4.6 you can now use the nameof() expression:
WeakEventManager<IMyGrid, MyEventArgs>.AddHandler(myGrid, nameof(IMyGrid.MouseDown), OnMouseDown);
What you could do is use the built-in System.ComponentModel.EventHandlerList. This class is a container for all of your object's event handler delegates. The primary benefit is that no storage is allocated on your object for each event unless there is actually someone subscribed to an event.
The secondary benefit is that in order to use it, you must provide a key for your event.
class MyObject
{
protected EventHandlerList Events = new EventHandlerList();
public static Event1Key = new object();
public event Event1
{
add { Events.AddHandler(Event1Key, value); }
remove { Events.RemoveHandler(Event1Key, value); }
}
}
Now you could create a variation of WeakEventManager that accepted keys rather than string names. So the consumer could say
WeakEventManager<EventSource, SomeEventEventArgs>.AddHandler(source, EventSource.Event1Key, source_SomeEvent);
Typically we use this code:
private EventHandler _updateErrorIcons;
public event EventHandler UpdateErrorIcons
{
add { _updateErrorIcons += value; }
remove { _updateErrorIcons -= value; }
}
Is there a similar shortcut like with automatic properties?
Something like:
public event EventHandler UpdateErrorIcons { add; remove; }
Yep. Get rid of the { add; remove; } part and the backing delegate field and you're golden:
public event EventHandler UpdateErrorIcons;
That's it!
Let me just add that before you asked this question, I hadn't even thought about the fact that the auto-implemented version of events is inconsistent with that of properties. Personally, I would actually prefer it if auto-implemented events worked the way you first attempted in your question. It would be more consistent, and it would also serve as a mental reminder that events are not identical to delegate fields, just like properties are not identical to regular fields.
Honestly, I think you're the rare exception where you actually knew about the custom syntax first. A lot of .NET developers have no clue there's an option to implement your own add and remove methods at all.
Update: Just for your own peace of mind, I have confirmed using Reflector that the default implementation of events in C# 4 (i.e., the implementation that gets generated when you go the auto-implemented route) is equivalent to this:
private EventHandler _updateErrorIcons;
public event EventHandler UpdateErrorIcons
{
add
{
EventHandler current, original;
do
{
original = _updateErrorIcons;
EventHandler updated = (EventHandler)Delegate.Combine(original, value);
current = Interlocked.CompareExchange(ref _updateErrorIcons, updated, original);
}
while (current != original);
}
remove
{
// Same deal, only with Delegate.Remove instead of Delegate.Combine.
}
}
Note that the above utilizes lock-free synchronization to effectively serialize add and remove calls. So if you're using the latest C# compiler, you don't need to implement add/remove yourself even for synchronization.
public event EventHandler UpdateErrorIcons;
is just fine
you can use
yourObbject.UpdateErrorIcons += YourFunction;
add {} and remove {} are used only in special cases where you need to handle event hookups manually. Us mere mortals normally just use public event EventHandler UpdateErrorIcons; where "EventHandler" is the delegate of choice.
For instance:
public delegate void MyEventDelegate(object sender, string param1);
public event MyEventDelegate MyEvent;
Note that because MyEvent is null if it doesn't have any listeners you need to check if it is null before invoking it. A standard method for doing this check is:
public void InvokeMyEvent(string param1)
{
MyEventDelegate myEventDelegate = MyEvent;
if (myEventDelegate != null)
myEventDelegate(this, param1);
}
A key element in this check is to make a copy of the object in question first and then work only on the copy. If not you could get a rare race condition where another thread unhooks between your if and your call.
Is there some hidden class property which would allow to know this ?
If you have access to the actual delegate (if you're using the shorthand event syntax, then this is only within the actual declaring class, as the delegate is private), then you can call GetInvocationList().
For instance:
public event EventHandler MyEvent;
To get the list of subscribers, you can call:
Delegate[] subscribers = MyEvent.GetInvocationList();
You can then inspect the Method and Target properties of each element of the subscribers array, if necessary.
The reason this works is because declaring the event as we did above actually does something akin to this:
private EventHandler myEventDelegate;
public event EventHandler MyEvent
{
add { myEventDelegate += value; }
remove { myEventDelegate -= value; }
}
This is why the event looks different when viewed from within the declaring class compared to anywhere else (including classes that inherit from it). The only public-facing interface is the add and remove functionality; the actual delegate, which is what holds the subscriptions, is private.