I know the following two methods work, but I wonder if one is better in terms of performance / maintenance / whatever.
The short way:
public event EventHandler MyEvent;
The long way:
private EventHandler _myEvent;
public event EventHandler MyEvent
{
add { _myEvent += value; }
remove { _myEvent -= value; }
}
The long way seems similar to encapsulating members with properties, which is indeed a good practice. But does this apply to event handlers?
In this case, the argument of "good practice" is a little tricker; the first is a "field-like event"; you note:
The long way seems similar to encapsulating members with properties,
but: this is encapsulated (behind add/remove) either way; so by comparison to properties, it is really the difference between:
public int Foo {get;set;}
and
private int foo;
public int Foo {
get { return foo; }
set { foo = value; }
}
In which case I would say "use the first one unless you have an actual reason not to" - it is still hidden behind accessors. Additionally, it is important to note that your second example is not what a field-like event (the first example) expands to : the compiler adds thread-safety into the mix. So: I would say use the first sample:
public event EventHandler MyEvent;
Note that the "how" for the thread-safety depends on which compiler version (and indeed, which specification) you use. In recent Microsoft C# compilers, it does this with Interlocked operations (CompareExchange etc), so it does not require a dedicated private synchronization object.
The first way does exactly the same underneath with creating private EventHandler with the name MyEvent. When it's accessed within the class event handler is returned (i.e. no problem with calling delegate) when it's called outside of class (myClassInstance.MyEvent += SomeHandler/myClassInstance.MyEvent -= SomeHandler) Add/Remove methods are called respectively. And these methods are the same (except they add thread-safety) as those you've written in the second way.
So why do you want to write more code when you actually don't need it?
To check what Marc Gravel mean i tried the following code:
public event EventHandler MyEventShortWay;
private EventHandler _myEvent;
public event EventHandler MyEventLongWay
{
add { _myEvent += value; }
remove { _myEvent -= value; }
}
I was surprised by what was generated (I edited the decompiled variable name) :
private EventHandler _myEventShortWay;
public event EventHandler MyEventShortWay
{
add
{
EventHandler handler2;
EventHandler myEventShortWay = this._myEventShortWay;
do
{
handler2 = myEventShortWay;
EventHandler handler3 = (EventHandler)Delegate.Combine(handler2, value);
myEventShortWay = Interlocked.CompareExchange<EventHandler>(ref this._myEventShortWay, handler3, handler2);
}
while (myEventShortWay != handler2);
}
remove
{
EventHandler handler2;
EventHandler myEventShortWay = this._myEventShortWay;
do
{
handler2 = myEventShortWay;
EventHandler handler3 = (EventHandler)Delegate.Remove(handler2, value);
myEventShortWay = Interlocked.CompareExchange<EventHandler>(ref this._myEventShortWay, handler3, handler2);
}
while (myEventShortWay != handler2);
}
}
private EventHandler _myEvent;
public event EventHandler MyEventLongWay
{
add
{
this._myEvent = (EventHandler) Delegate.Combine(this._myEvent, value);
}
remove
{
this._myEvent = (EventHandler)Delegate.Remove(this._myEvent, value);
}
}
Related
Why can´t we raise an event with a custom implementation, while it is possible without them? See this code:
public class Program
{
private EventHandler myEvent;
public event EventHandler MyEvent
{
add { myEvent += value; }
remove { myEvent -= value; }
}
public event EventHandler AnotherEvent;
public static void Main()
{
var target = new Program();
target.MyEvent(null, null); // ERROR CS0079
target.AnotherEvent(null, null); // compiles
}
}
You see both events are declared within my class. While target.AnotherEvent(...) compiles just fine, target.MyEvent(...) does not:
The Event MyEvent can only appear on the left hand side of += or -=.
I Know an event is just a delegate with an add- and remove-method. So AnotherEvent is translated by the compiler to an add- and a remove-method:
private EventHandler _AnotherEvent;
public event EventHandler AnotherEvent
{
add { _AnotherEvent += value; }
remove { _AnotherEvent -= value; }
}
So I assume the call to AnotherEvent is replaced by the compiler to a call to the private delegate, which was _AnotherEvent(...).
Did I get this right? Are there any docs about why the second call works while the former does not? Or at least any description about what the compiler does here?
When an auto event is used public event EventHandler AnotherEvent;. The compiler will create a field (and some methods) for it and invoking is done on that field. So the public event does not exists anymore. It's syntactic sugar.
So invoking a non-auto event is not possible. Because it isn't found in the compiled code. It's replaced by add_, remove_ methods. You can only invoke on the private field (which is generated)
This explains why you cannot invoke an event outside the class instance.
It doesn't work because there is simply now way to get the actual invokeable event handler. As you have noted, there is just an add and remove, not a get.
The generated code for the event handler is:
.event [mscorlib]System.EventHandler MyEvent
{
.addon instance void ConsoleApp1.Program::add_MyEvent(class [mscorlib]System.EventHandler)
.removeon instance void ConsoleApp1.Program::remove_MyEvent(class [mscorlib]System.EventHandler)
} // end of event Program::MyEvent
It adds two method references, one for add and one for remove. If you look at it, how would it know what method to invoke? What if add and remove are much more complex than they are now? There is just no way to know for sure what event handler to call.
It's syntactical sugar. That you can call AnotherEvent like the backing field is a convenience provided by the compiler (AnotherEvent is a so-called field-like event). Once you add your own accessors, the event declaration ceases to be a field-like event and has to be invoked through its backing field.
See the relevant part of the C# Language Specification:
Field-like events
Within the program text of the class or struct that contains the declaration of an event, certain events can be used like fields. To be
used in this way, an event must not be abstract or extern, and must
not explicitly include event_accessor_declarations. Such an event can
be used in any context that permits a field. The field contains a
delegate (Delegates) which refers to the list of event handlers that
have been added to the event. If no event handlers have been added,
the field contains null.
(emphasis mine)
It is recommended that you lock the event before you add or remove a new event handler method.
saying that, have a look on this piece of code:
public event EventHandler MyEvent
{
add
{
lock (objectLock)
{
myEvent += value;
}
}
remove
{
lock (objectLock)
{
myEvent -= value;
}
}
}
The reason public event EventHandler AnotherEvent; works is because When no custom event accessors are supplied in your code, the compiler will add them automatically.
Follow this doc, How to: Implement Custom Event Accessors in order to get more details about the proper implementation and this post for another source.
Regarding the implementation:
private EventHandler myEvent;
public event EventHandler MyEvent
{
add
{
lock (objectLock)
{
myEvent += value;
}
}
remove
{
lock (objectLock)
{
myEvent -= value;
}
}
}
public event EventHandler AnotherEvent;
public static void Main()
{
var target = new Program();
var myEvent = target.MyEvent;
myEvent?.Invoke(EventArgs.Empty, EventArgs.Empty);
target.AnotherEvent(null, null);
}
Edit to explain the implementation:
var myEvent = target.MyEvent;
With an explicit event, you have to provide your own backing store - either a delegate field or something like EventHandlerList, so we just go with var here.
Could someone explain the meaning of the following portion of code :
private event UserChangedHandler m_UserChanged;
public event UserChangedHandler UserChanged
{
add
{
if (m_UserChanged != value)
{
m_UserChanged += value;
}
}
}
thanks
add { } is a construct much like get { } for properties, except add works on events. You're defining custom functionality here when adding delegates to an event.
In this case, this method body prevents consecutive duplicates (i.e. you can't register the same method/handler twice in a row).
So in this example:
public void HandlerUserChanged(object o, UserChangedEventArgs args)
{
// some code
}
public void HandlerUserChanged2(object o, UserChangedEventArgs args)
{
// some code
}
Later:
UserChanged += HandleUserChanged;
UserChanged += HandleUserChanged;
UserChanged(this, new UserChangedEventArgs());
The method HandleUserChanged will only fire once, even though you registered it twice. A normal event (without the add { }) would invoke the function twice.
However:
UserChanged += HandleUserChanged;
UserChanged += HandleUserChanged2;
UserChanged += HandleUserChanged;
UserChanged(this, new UserChangedEventArgs());
Will allow HandleUserChanged to fire twice, because the last-registered handler isn't ever the one being added. The == operator on events works on the LAST handler. (Thankyou to Matthew for bringing that to attention)
It strikes me as odd that m_UserChanged is declared as an event rather than just a delegate instance (is that the right terminology...I get confused w/ delegates). Events are analogous to a simple Property model in that they essentially wrap underlying fields within a pair of transparent methods.
The way I understand it, .Net allows for the creation of implcit (anonymous?) event and properties by taking something like this :
public int Value { get; set;}
public event EventHandler ValueChanged;
and then creating the respective underlying placeholder objects to generate something more like this:
private int _Value;
public int Value { get { return _Value;} set { _Value = value;}}
private EventHandler _ValueChanged;
public event EventHandler ValueChange { add { _ValueChanged += value;} remove { _ValueChanged -= value;}}
The underlying object can be defined explicitly of course, but what the code sample above looks like is a bit of a conflation between explicit and implicit event declaration...it looks like the following is actually being done (behind the scenes, as it were):
private UserChangedHandler _m_UserChanged;
private event UserChangedHandler m_UserChanged { add { _m_UserChanged += value;} remove { _m_UserChanged -= value;}}
public event UserChangedHandler UserChanged
{
add
{
if (m_UserChanged != value)
{
m_UserChanged += value;
}
}
}
It doesn't really matter in the grand scheme of things, I don't guess, but it looks like an oversight.
I am sure that I am just not understanding something fundamental about events and/or delegates in C#, but why can't I do the Boolean tests in this code sample:
public class UseSomeEventBase {
public delegate void SomeEventHandler(object sender, EventArgs e);
public event SomeEventHandler SomeEvent;
protected void OnSomeEvent(EventArgs e) {
// CANONICAL WAY TO TEST EVENT. OF COURSE, THIS WORKS.
if (SomeEvent != null) SomeEvent(this, e);
}
}
public class UseSomeEvent : UseSomeEventBase {
public bool IsSomeEventHandlerNull() {
// "LEFT HAND SIDE" COMPILER ERROR
return SomeEvent == null;
}
}
class Program {
static void Main(string[] args) {
var useSomeEvent = new UseSomeEvent();
useSomeEvent.SomeEvent +=new UseSomeEventBase.SomeEventHandler(FuncToHandle);
// "LEFT HAND SIDE" COMPILER ERROR
if (useSomeEvent.SomeEvent == null) {
}
var useSomeEventBase = new UseSomeEventBase();
useSomeEventBase.SomeEvent += new UseSomeEventBase.SomeEventHandler(FuncToHandle);
// "LEFT HAND SIDE" COMPILER ERROR
if (useSomeEventBase.SomeEvent == null) {
}
}
static void FuncToHandle(object sender, EventArgs e) { }
}
An event is really just an "add" operation and a "remove" operation. You can't get the value, you can't set the value, you can't call it - you can just subscribe a handler for the event (add) or unsubscribe one (remove). This is fine - it's encapsulation, plain and simple. It's up to the publisher to implement add/remove appropriately, but unless the publisher chooses to make the details available, subscribers can't modify or access the implementation-specific parts.
Field-like events in C# (where you don't specify the add/remove bits) hide this - they create a variable of a delegate type and an event. The event's add/remove implementations just use the variable to keep track of the subscribers.
Inside the class you refer to the variable (so you can get the currently subscribed delegates, execute them etc) and outside the class you refer to the event itself (so only have add/remove abilities).
The alternative to field-like events is where you explicitly implement the add/remove yourself, e.g.
private EventHandler clickHandler; // Normal private field
public event EventHandler Click
{
add
{
Console.WriteLine("New subscriber");
clickHandler += value;
}
remove
{
Console.WriteLine("Lost a subscriber");
clickHandler -= value;
}
}
See my article on events for more information.
Of course the event publisher can also make more information available - you could write a property like ClickHandlers to return the current multi-cast delegate, or HasClickHandlersto return whether there are any or not. That's not part of the core event model though.
You can easily use a very simple approach here to not repeatedly subscribe to an event.
Either of the 2 approaches below can be used:
Flag approach : _getWarehouseForVendorCompletedSubscribed is a private variable initialized to false.
if (!_getWarehouseForVendorCompletedSubscribed)
{
_serviceClient.GetWarehouseForVendorCompleted += new EventHandler<GetWarehouseForVendorCompletedEventArgs>(_serviceClient_GetWarehouseForVendorCompleted);
_getWarehouseForVendorCompletedSubscribed = true;
}
Unsubscribe Approach :Include an unsubscribe everytime you want to subscribe.
_serviceClient.GetWarehouseForVendorCompleted -= new
EventHandler<GetWarehouseForVendorCompletedEventArgs>
(_serviceClient_GetWarehouseForVendorCompleted);
_serviceClient.GetWarehouseForVendorCompleted += new
EventHandler<GetWarehouseForVendorCompletedEventArgs>
(_serviceClient_GetWarehouseForVendorCompleted);
Here the answer:
using System;
delegate void MyEventHandler();
class MyEvent
{
string s;
public event MyEventHandler SomeEvent;
// This is called to raise the event.
public void OnSomeEvent()
{
if (SomeEvent != null)
{
SomeEvent();
}
}
public string IsNull
{
get
{
if (SomeEvent != null)
return s = "The EventHandlerList is not NULL";
else return s = "The EventHandlerList is NULL"; ;
}
}
}
class EventDemo
{
// An event handler.
static void Handler()
{
Console.WriteLine("Event occurred");
}
static void Main()
{
MyEvent evt = new MyEvent();
// Add Handler() to the event list.
evt.SomeEvent += Handler;
// Raise the event.
//evt.OnSomeEvent();
evt.SomeEvent -= Handler;
Console.WriteLine(evt.IsNull);
Console.ReadKey();
}
}
Here's a slightly different question
What value is there in testing an externally defined event for null?
As an external consumer of an event you can only do 2 operations
Add a handler
Remove a handler
The null or non-nullness of the event has no bearing on these 2 actions. Why do you want to run a test which provides no perceivable value?
It's a rule in place when using the 'event' keyword. When you create an event, you are restricting outside class interaction with the delegate to a "subscribe / unsubscribe" relationship, this includes cases of inheritance. Remember an event is essentially a property, but for method calls, it isn't really an object itself, so really it looks more like this:
public event SomeEventHandler SomeEvent
{
add
{
//Add method call to delegate
}
remove
{
//Remove method call to delegate
}
}
You'd have to do that from the base class. That's the exact reason that you did this:
protected void OnSomeEvent(EventArgs e) {
// CANONICAL WAY TO TEST EVENT. OF COURSE, THIS WORKS.
if (SomeEvent != null) SomeEvent(this, e);
}
You can't access events from a derived class. Also, you should make that method virtual, so that it can be overridden in a derived class.
Publisher of the event implicitly overload only += and -= operations, and other operations are not implemented in the publisher because of the obvious reasons as explained above, such as don't want to give control to subscriber to change events.
If we want to validate if a particular event is subscribed in the subscriber class, better publisher will set a flag in its class when event is subscriber and clear the flag when it is unsubscriber.
If subscriber can access the flag of publisher, very easily identifiable whether the particular event is subscriber or not by checking the flag value.
I started with a question, and in typing the question, found the answer, but instead of deleting, I thought it might be helpful to A) get confirmation, and B) help others.
If I have an event, and several places in the application add listeners, what is the best way to remove all listeners at once? For example, I can ...
myPage.OnPageOpened += OpenPage;
and later in my code ...
myPage.OnPageOpened -= OpenPage;
But what if I have unknown 3rd party subscribers and I want to press a magic Reset button that clears everything and starts from scratch?
You can use += and -= operators anywhere against the EventHandler, because the operator overloads are public. The = overloaded operator is private it can only be called in the defining class.
So in the defining class I can use this to clear my EventHandler.
OnPageOpened = null;
And to expose that functionality, I could ...
public void ClearPageOpenedEvents() {
OnPageOpened = null;
}
Is that correct?
Yes, you are correct. The reason for this is that the compiler creates a private delegate object under the covers, like this:
private EventHandler pageOpened;
public EventHandler PageOpened
{
add { pageOpened += value; }
remove { pageOpened -= value; }
}
Inside your class, you have a reference to the private delegate instance, so that's why you can do the assignment. You definitely want to expose a method to clear the targets if that's functionality you need; you don't want to expose the delegate itself.
That's the way to do it, but how does something outside the class know that the class should drop all its event listeners? What if someone extending/using your code is expecting that event on an ongoing basis?
You can use the assignment operator on an event because that's how adding and removing events work. Using Reflector shines a lot of light on how events are done in C#.
Given the simple class of
public class MyClass
{
public event EventHandler MyEvent;
}
The following code is produced when compiled
public class MyClass
{
private EventHandler MyEvent;
public event EventHandler MyEvent;
}
So when you are referencing MyEvent you are referring to the private delegate variable MyEvent. The += and -= operators are "special" (because they aren't operators) and get changed into calling the add and remove methods that are created for the event (which use the assignment operator themselves).
[MethodImpl(MethodImplOptions.Synchronized)]
public void add_MyEvent(EventHandler value)
{
this.MyEvent = (EventHandler) Delegate.Combine(this.MyEvent, value);
}
[MethodImpl(MethodImplOptions.Synchronized)]
public void remove_MyEvent(EventHandler value)
{
this.MyEvent = (EventHandler) Delegate.Remove(this.MyEvent, value);
}
I'm using C#, .NET 3.5. I understand how to utilize events, how to declare them in my class, how to hook them from somewhere else, etc. A contrived example:
public class MyList
{
private List<string> m_Strings = new List<string>();
public EventHandler<EventArgs> ElementAddedEvent;
public void Add(string value)
{
m_Strings.Add(value);
if (ElementAddedEvent != null)
ElementAddedEvent(value, EventArgs.Empty);
}
}
[TestClass]
public class TestMyList
{
private bool m_Fired = false;
[TestMethod]
public void TestEvents()
{
MyList tmp = new MyList();
tmp.ElementAddedEvent += new EventHandler<EventArgs>(Fired);
tmp.Add("test");
Assert.IsTrue(m_Fired);
}
private void Fired(object sender, EventArgs args)
{
m_Fired = true;
}
}
However, what I do not understand, is when one declares an event handler
public EventHandler<EventArgs> ElementAddedEvent;
It's never initialized - so what, exactly, is ElementAddedEvent? What does it point to? The following won't work, because the EventHandler is never initialized:
[TestClass]
public class TestMyList
{
private bool m_Fired = false;
[TestMethod]
public void TestEvents()
{
EventHandler<EventArgs> somethingHappend;
somethingHappend += new EventHandler<EventArgs>(Fired);
somethingHappend(this, EventArgs.Empty);
Assert.IsTrue(m_Fired);
}
private void Fired(object sender, EventArgs args)
{
m_Fired = true;
}
}
I notice that there is an EventHandler.CreateDelegate(...), but all the method signatures suggest this is only used for attaching Delegates to an already existing EventHandler through the typical ElementAddedEvent += new EventHandler(MyMethod).
I'm not sure if what I am trying to do will help... but ultimately I'd like to come up with an abstract parent DataContext in LINQ whose children can register which table Types they want "observed" so I can have events such as BeforeUpdate and AfterUpdate, but specific to types. Something like this:
public class BaseDataContext : DataContext
{
private static Dictionary<Type, Dictionary<ChangeAction, EventHandler>> m_ObservedTypes = new Dictionary<Type, Dictionary<ChangeAction, EventHandler>>();
public static void Observe(Type type)
{
if (m_ObservedTypes.ContainsKey(type) == false)
{
m_ObservedTypes.Add(type, new Dictionary<ChangeAction, EventHandler>());
EventHandler eventHandler = EventHandler.CreateDelegate(typeof(EventHandler), null, null) as EventHandler;
m_ObservedTypes[type].Add(ChangeAction.Insert, eventHandler);
eventHandler = EventHandler.CreateDelegate(typeof(EventHandler), null, null) as EventHandler;
m_ObservedTypes[type].Add(ChangeAction.Update, eventHandler);
eventHandler = EventHandler.CreateDelegate(typeof(EventHandler), null, null) as EventHandler;
m_ObservedTypes[type].Add(ChangeAction.Delete, eventHandler);
}
}
public static Dictionary<Type, Dictionary<ChangeAction, EventHandler>> Events
{
get { return m_ObservedTypes; }
}
}
public class MyClass
{
public MyClass()
{
BaseDataContext.Events[typeof(User)][ChangeAction.Update] += new EventHandler(OnUserUpdate);
}
public void OnUserUpdated(object sender, EventArgs args)
{
// do something
}
}
Thinking about this made me realize I don't really understand what's happening under the hod with events - and I would like to understand :)
I've written this up in a fair amount of detail in an article, but here's the summary, assuming you're reasonably happy with delegates themselves:
An event is just an "add" method and a "remove" method, in the same way that a property is really just a "get" method and a "set" method. (In fact, the CLI allows a "raise/fire" method as well, but C# never generates this.) Metadata describes the event with references to the methods.
When you declare a field-like event (like your ElementAddedEvent) the compiler generates the methods and a private field (of the same type as the delegate). Within the class, when you refer to ElementAddedEvent you're referring to the field. Outside the class, you're referring to the field.
When anyone subscribes to an event (with the += operator) that calls the add method. When they unsubscribe (with the -= operator) that calls the remove.
For field-like events, there's some synchronization but otherwise the add/remove just call Delegate.Combine/Remove to change the value of the auto-generated field. Both of these operations assign to the backing field - remember that delegates are immutable. In other words, the autogenerated code is very much like this:
// Backing field
// The underscores just make it simpler to see what's going on here.
// In the rest of your source code for this class, if you refer to
// ElementAddedEvent, you're really referring to this field.
private EventHandler<EventArgs> __ElementAddedEvent;
// Actual event
public EventHandler<EventArgs> ElementAddedEvent
{
add
{
lock(this)
{
// Equivalent to __ElementAddedEvent += value;
__ElementAddedEvent = Delegate.Combine(__ElementAddedEvent, value);
}
}
remove
{
lock(this)
{
// Equivalent to __ElementAddedEvent -= value;
__ElementAddedEvent = Delegate.Remove(__ElementAddedEvent, value);
}
}
}
The initial value of the generated field in your case is null - and it will always become null again if all subscribers are removed, as that is the behaviour of Delegate.Remove.
If you want a "no-op" handler to subscribe to your event, so as to avoid the nullity check, you can do:
public EventHandler<EventArgs> ElementAddedEvent = delegate {};
The delegate {} is just an anonymous method which doesn't care about its parameters and does nothing.
If there's anything that's still unclear, please ask and I'll try to help!
Under the hood, events are just delegates with special calling conventions. (For example, you don't have to check for nullity before raising an event.)
In pseudocode, Event.Invoke() breaks down like this:
If Event Has Listeners
Call each listener synchronously on this thread in arbitrary order.
Since events are multicast, they will have zero or more listeners, held in a collection. The CLR will loop through them, calling each in an arbitrary order.
One big caveat to remember is that event handlers execute in the same thread as the event is raised in. It's a common mental error to think of them as spawning a new thread. They do not.