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).
Related
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);
}
}
I have an event in a loop. I am trying to prevent the same method being added to an event more than once. I've implemented the add and remove accessors.
However, I get an error stating that:
ItemsProcessed can only appear on the left hand side of += or -=
When I try to call them, even within the same class.
ItemsProcessed(this, new EventArgs()); // Produces error
public event EventHandler ItemsProcessed
{
add
{
ItemsProcessed -= value;
ItemsProcessed += value;
}
remove
{
ItemsProcessed -= value;
}
}
With an explicit event, you need to provide your own backing store - either a delegate field or something like EventHandlerList. The current code is recursive. Try:
private EventHandler itemsProcessed;
public event EventHandler ItemsProcessed
{
add
{
itemsProcessed-= value;
itemsProcessed+= value;
}
remove
{
itemsProcessed-= value;
}
}
Then (and noting I'm being a little cautious about the "about to turn null" edge-case re threading):
var snapshot = itemsProcessed;
if(snapshot != null) snapshot(this, EventArgs.Empty);
With more recent C# versions, this can be simplified:
itemsProcessed?.Invoke(this, EventArgs.Empty);
I can't tell from your post if you are trying to raise the event from a derived class or not, but one thing I've found is that you can't define an event in a base class and then raise it (directly) in a derived class, for some reason that isn't real clear to me yet.
So I define protected functions in base classes to raise events (that are defined in those base classes), like this:
// The signature for a handler of the ProgressStarted event.
// title: The title/label for a progress dialog/bar.
// total: The max progress value.
public delegate void ProgressStartedType(string title, int total);
// Raised when progress on a potentially long running process is started.
public event ProgressStartedType ProgressStarted;
// Used from derived classes to raise ProgressStarted.
protected void RaiseProgressStarted(string title, int total) {
if (ProgressStarted != null) ProgressStarted(title, total);
}
Then in the derived class, I call RaiseProgressStarted(title, total) instead of calling ProgressStarted(title, total).
It seems like kind of the long way around. Maybe someone else knows of a better way around this problem.
It seems that if you implement the EventHandler explicitly, you can't refer to the 'Property' when firing the event. You must refer to the backing store.
What error? I guess its stack overflow error, because you are calling add and remove on yourserlf (same event). Also you cannot raise event ACCESSOR.
Valid way to do this is to create backing private event, that will be added and removed to from public accessor, and you should raise this private event.
Dang, minute late.
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 have declared a generic event handler
public delegate void EventHandler();
to which I have added the extension method 'RaiseEvent':
public static void RaiseEvent(this EventHandler self) {
if (self != null) self.Invoke();
}
When I define the event using the typical syntax
public event EventHandler TypicalEvent;
then I can call use the extension method without problems:
TypicalEvent.RaiseEvent();
But when I define the event with explicit add/remove syntax
private EventHandler _explicitEvent;
public event EventHandler ExplicitEvent {
add { _explicitEvent += value; }
remove { _explicitEvent -= value; }
}
then the extension method does not exist on the event defined with explicit add/remove syntax:
ExplicitEvent.RaiseEvent(); //RaiseEvent() does not exist on the event for some reason
And when I hover over to event to see the reason it says:
The event 'ExplicitEvent' can only
appear on the left hand side of += or
-=
Why should an event defined using the typical syntax be different from an event defined using the explicit add/remove syntax and why extension methods do not work on the latter?
EDIT: I found I can work around it by using the private event handler directly:
_explicitEvent.RaiseEvent();
But I still don't understand why I cannot use the event directly like the event defined using the typical syntax. Maybe someone can enlighten me.
When you create a "field-like" event, like this:
public event EventHandler Foo;
the compiler generates a field and an event. Within the source code of the class which declares the event, any time you refer to Foo the compiler understand that you're referring to the field. However, the field is private, so any time you refer to Foo from other classes, it refers to the event (and therefore the add/remove code).
If you declare your own explicit add/remove code, you don't get an auto-generated field. So, you've only got an event, and you can't raise an event directly in C# - you can only invoke a delegate instance. An event isn't a delegate instance, it's just an add/remove pair.
Now, your code contained this:
public EventHandler TypicalEvent;
This is slightly different still - it wasn't declaring an event at all - it was declaring a public field of the delegate type EventHandler. Anyone can invoke that, because the value is just a delegate instance. It's important to understand the difference between a field and an event. You should never write this kind of code, just as I'm sure you don't normally have public fields of other types such as string and int. Unfortunately it's an easy typo to make, and a relatively hard one to stop. You'd only spot it by noticing that the compiler was allowing you to assign or use the value from another class.
See my article on events and delegates for more information.
Because you can do this (it's non-real-world sample, but it "works"):
private EventHandler _explicitEvent_A;
private EventHandler _explicitEvent_B;
private bool flag;
public event EventHandler ExplicitEvent {
add {
if ( flag = !flag ) { _explicitEvent_A += value; /* or do anything else */ }
else { _explicitEvent_B += value; /* or do anything else */ }
}
remove {
if ( flag = !flag ) { _explicitEvent_A -= value; /* or do anything else */ }
else { _explicitEvent_B -= value; /* or do anything else */ }
}
}
How can the compiler know what it should do with "ExplicitEvent.RaiseEvent();"?
Answer: It can't.
The "ExplicitEvent.RaiseEvent();" is only syntax sugar, which can be predicated only if the event is implicitly implemented.
That's because you're not looking at it right.
The logic is the same as in Properties.
Once you've set the add/remove it's no longer an actual event, but a wrapper to expose the actual event (events can only be triggered from inside the class itself, so you always have access locally to the real event).
private EventHandler _explicitEvent;
public event EventHandler ExplicitEvent {
add { _explicitEvent += value; }
remove { _explicitEvent -= value; }
}
private double seconds;
public double Hours
{
get { return seconds / 3600; }
set { seconds = value * 3600; }
}
In both cases the member with the get/set or add/remove property doesn't really contain any data. You need a "real" private member to contain the actual data.
The properties just allow you program extra logic when exposing the members to outside world.
A good example for WHY you'd want to do it, is to stop extra computation when it's not needed (no one is listening to the event).
For example, lets say the events are triggered by a timer, and we don't want the timer to work if no-one is registered to the event:
private System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
private EventHandler _explicitEvent;
public event EventHandler ExplicitEvent
{
add
{
if (_explicitEvent == null) timer.Start();
_explicitEvent += value;
}
remove
{
_explicitEvent -= value;
if (_explicitEvent == null) timer.Stop();
}
}
You'd probably want to lock the add/remove with an object (an afterthought)...
The "plain" declaration for TypicalEvent does some compiler trickery. It creates an event metadata entry, add and remove methods and a backing field. When your code refers to TypicalEvent, the compiler translates it into a reference to the backing field; when external code refers to TypicalEvent (using += and -=), the compiler translates it into a reference to the add or remove method.
The "explicit" declaration bypasses this compiler trickery. You are spelling out the add and remove methods and the backing field: indeed, as TcKs points out, there may not even be a backing field (this is a common reason for using the explicit form: see e.g. events in System.Windows.Forms.Control). Therefore the compiler can no longer quietly translate the reference to TypicalEvent into a reference to the backing field: if you want the backing field, the actual delegate object, you have to reference the backing field directly:
_explicitEvent.RaiseEvent()
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);
}