event delegate (in)equality? - c#

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.

Related

C# . Explanation about the code converted from VB

I am using a converter that converted the following VB code
Public Event Progress(ByVal Percent As Integer)
to C#
public delegate void ProgressEventHandler(int Percent);
private ProgressEventHandler ProgressEvent;
public event ProgressEventHandler Progress
{
add
{
ProgressEvent = (ProgressEventHandler) System.Delegate.Combine(ProgressEvent, value);
}
remove
{
ProgressEvent = (ProgressEventHandler) System.Delegate.Remove(ProgressEvent, value);
}
}
That seems quite a lot of code. I was expecting just these 3 lines.
public delegate void ProgressEventHandler(int Percent);
private ProgressEventHandler ProgressEvent;
public event ProgressEventHandler Progress;
and then later I invoke the event in this way
void OnProgress(int p) {
ProgressEvent?.Invoke (p);
}
So what exactly I need to know is what is the advantage of the Progress body (with add and remove). Should I stick to my own code or use the code by the converter? Which one is better?
Those System.Delegate.Combine and System.Delegate.Remove calls are just verbose ways of doing the following:
// combine
ProgressEvent += value;
// remove
ProgressEvent -= value;
Which turns the event member into the following:
private ProgressEventHandler ProgressEvent;
public event ProgressEventHandler Progress
{
add
{
ProgressEvent += value;
}
remove
{
ProgressEvent -= value;
}
}
And at that time, it’s equivalent to the auto-implemented event member:
public event ProgressEventHandler Progress;
So, this is essentially just a verbose way of defining the event and event handler, but which really means just the same. I assume that the converter that you were using just uses the verbose way to be able to handle non-standard solutions easier. And maybe it is generating this from the compiled IL, at which point this all looks more or less the same.
Btw. your expected code won’t work since the Progress event and the handler ProgressEvent are not linked (so if you want to split those members, you need to implement the event explicitly).

How to assign the same method to multiple delegates

Is it possible to assign the same method to multiple delegates all at once?
public class Hoge
{
public event Action EventA;
public event Action EventB;
public event Action EventC;
public Hoge()
{
EventA += () => FugaMethod();
EventB += () => FugaMethod();
EventC += () => FugaMethod();
}
private void FugaMethod()
{
Console.WriteLine("Hello.");
}
}
I'd like to simplify the assignments of the FugaMethod().
since events can't go as a parameter ... unfortunately ... no
if we are talking about a shitload of events, reflection would be the way to go ... but that i'd not really call "simplification"
edit:
for clarification:
what you can pass as a parameter:
the current list of eventhandlers attached to a static or specific event on a specific object (what you pass in this case is not the event, but a MulticastDelegate)
what you can not pass as a parameter: the event itself ...
you are not able to pass an event in a direct way that would allow to attach another event handler ... for that you would probably want to pass the specific obect instance, the EventInfo describing the event itself, and the new handler(s) ...
regarding "simplification":
what you need to do would be:
-use reflection to obtain the EventInfo objects of the desired events
-for each instance and each EventInfo call EventInfo.AddEventHandler, passing the instance as target and the eventhandler as handler
since you cannot pass the event as a parameter, you cannot extract a simple and typesafe method to get the desired EventInfo objects. you will have to use some selection by name, or other logic that takes the instance type apart by using Type.getEvent or Type.getEvents
so, if you are not handling a shitload of events, like a few hundred, writing it like you did seems to be the preferable way to go ... the reflection approach will be anything but simpler or shorter
There is a way to assign multiple event handlers at once that does not require reflection however itäs not trivial and some programming is necessary. You can use a dictionary to store your events if you want initialize them in a loop.
As a side note: by convention the event keyword should only be used if the delegate is of type EventHandler. It may and probably will confuse others when they try to use it.
Hoge class:
public class Hoge
{
// A dictionary to store your events.
private Dictionary<string, EventHandler> events = new Dictionary<string, EventHandler>()
{
{ "EventA", null },
{ "EventB", null },
{ "EventC", null }
};
// Event add/remove accessors.
public event EventHandler EventA
{
add
{
lock (events)
{
events["EventA"] += (EventHandler)events["EventA"] + value;
}
}
remove
{
lock (events)
{
events["EventA"] += (EventHandler)events["EventA"] - value;
}
}
}
// You can do the same for other events.
public event EventHandler EventB;
public event EventHandler EventC;
public Hoge()
{
// Initialize events in a loop.
foreach (var key in events.Keys.ToList())
{
events[key] += FugaMethod;
}
}
// Raises EventA.
public void RaiseEventA()
{
EventHandler handler;
if (null != (handler = (EventHandler)events["EventA"]))
{
handler(this, EventArgs.Empty);
}
}
// Event handler.
private void FugaMethod(object sender, EventArgs e)
{
Console.WriteLine("Hello.");
}
}
Usage:
class Program
{
static void Main(string[] args)
{
new Hoge().RaiseEventA();
}
}
How to: Use a Dictionary to Store Event Instances (C# Programming Guide)
Handling and Raising Events

Best practice in declaring events in C#

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);
}
}

How does an EventHandler know to allow = operator only in defining class?

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);
}

How do C# Events work behind the scenes?

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.

Categories

Resources