Short way to write an event? - c#

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.

Related

Subscribing to events with = instead of +=

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 :)

WeakEventManager with event name lambda expression and custom event accessors

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

Embedded Mono: How do you raise an event in C++?

I'm working on an application that's embedding Mono, and I'd like to raise an event from the C++ layer into the C# layer. Here's what I have:
void* itr(NULL);
MonoEvent* monoEvent;
while(monoEvent= mono_class_get_events(klass, &itr))
{
if(0 == strcmp(eventName, mono_event_get_name(monoEvent)))
raiseMethod = mono_event_get_raise_method(monoEvent);
}
However, raiseMethod always comes back as NULL. Looking at the structure of the MonoEvent, it looks like the add and remove methods were populated, but not the raise? Is there something special I have to do to get this to work?
EDIT: If it matters, here's the (basic) form of the delegate, class, and events I'm using in the C# layer.
public delegate void MyHandler(uint id);
public class SimpleComponent : NativeComponent
{
public event MyHandler OnEnter;
public event MyHandler OnExit;
}
May the event be defined in parent class? If so you need to traverse up the class hierarchy with something like the following:
MonoEvent* monoEvent;
while (klass)
{
void* itr = NULL;
while(monoEvent= mono_class_get_events(klass, &itr))
{
if(0 == strcmp(eventName, mono_event_get_name(monoEvent)))
raiseMethod = mono_event_get_raise_method(monoEvent);
}
klass = mono_class_get_parent(klass);
}
EDIT after comment and re-reading question:
It is normal that the raise method for event is NULL.
This method usually returns null for events declared with the C# event keyword or the Visual Basic Event keyword. This is because the C# and Visual Basic compilers do not generate such a method by default.
(source)
I am afraid it may be hard to fire an event of a class. Because it is actually breaking the concept of events in .NET - which says that the class itself can only fire its own Event. Actually, even from C# it is hard to raise the event of other class.
Conceptually, events are pair of add_handler and remove_handler methods where you specify delegates to be called when event's circumstances occur. It is up to class how it implements events. Technically, it is just a private delegate field, AFAIK.
You may try to locate it.
I am not sure if it is a proper approach, but one of the answers in How do I raise an event via reflection in .NET/C#? describes how to raise event using reflection. You might attempt to convert it into mono_class / mono_field calls, etc.
Krizz's answer is the most complete. This is how I fixed my code to work how I would "expect".
I changed the C# side to:
public delegate void MyHandler(uint aEntityId);
public class SimpleComponent: NativeComponent
{
public event MyHandler OnEnter;
public event MyHandler OnExit;
protected void CallOnEnter(uint aEntityId)
{
if (OnEnter != null)
OnEnter(aEntityId);
}
protected void CallOnExit(uint aEntityId)
{
if (OnExit!= null)
OnExit(aEntityId);
}
}
Then grabbed the mono method with
raiseMethod = mono_class_get_method_from_name(klass, "CallOnEnter", 1);

Events Internals: In .net how are Events represented internally?

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).

C# pattern to prevent an event handler hooked twice [duplicate]

This question already has answers here:
How to ensure an event is only subscribed to once
(8 answers)
Closed 8 years ago.
Duplicate of: How to ensure an event is only subscribed to once
and Has an event handler already been added?
I have a singleton that provides some service and my classes hook into some events on it, sometimes a class is hooking twice to the event and then gets called twice.
I'm looking for a classical way to prevent this from happening. somehow I need to check if I've already hooked to this event...
How about just removing the event first with -= , if it is not found an exception is not thrown
/// -= Removes the event if it has been already added, this prevents multiple firing of the event
((System.Windows.Forms.WebBrowser)sender).Document.Click -= new System.Windows.Forms.HtmlElementEventHandler(testii);
((System.Windows.Forms.WebBrowser)sender).Document.Click += new System.Windows.Forms.HtmlElementEventHandler(testii);
Explicitly implement the event and check the invocation list. You'll also need to check for null:
using System.Linq; // Required for the .Contains call below:
...
private EventHandler foo;
public event EventHandler Foo
{
add
{
if (foo == null || !foo.GetInvocationList().Contains(value))
{
foo += value;
}
}
remove
{
foo -= value;
}
}
Using the code above, if a caller subscribes to the event multiple times, it will simply be ignored.
I've tested each solution and the best one (considering performance) is:
private EventHandler _foo;
public event EventHandler Foo {
add {
_foo -= value;
_foo += value;
}
remove {
_foo -= value;
}
}
No Linq using required. No need to check for null before cancelling a subscription (see MS EventHandler for details). No need to remember to do the unsubscription everywhere.
You really should handle this at the sink level and not the source level. That is, don't prescribe event handler logic at the event source - leave that to the handlers (the sinks) themselves.
As the developer of a service, who are you to say that sinks can only register once? What if they want to register twice for some reason? And if you are trying to correct bugs in the sinks by modifying the source, it's again a good reason for correcting these issues at the sink-level.
I'm sure you have your reasons; an event source for which duplicate sinks are illegal is not unfathomable. But perhaps you should consider an alternate architecture that leaves the semantics of an event intact.
You need to implement the add and remove accessors on the event, and then check the target list of the delegate, or store the targets in a list.
In the add method, you can use the Delegate.GetInvocationList method to obtain a list of the targets already added to the delegate.
Since delegates are defined to compare equal if they're linked to the same method on the same target object, you could probably run through that list and compare, and if you find none that compares equal, you add the new one.
Here's sample code, compile as console application:
using System;
using System.Linq;
namespace DemoApp
{
public class TestClass
{
private EventHandler _Test;
public event EventHandler Test
{
add
{
if (_Test == null || !_Test.GetInvocationList().Contains(value))
_Test += value;
}
remove
{
_Test -= value;
}
}
public void OnTest()
{
if (_Test != null)
_Test(this, EventArgs.Empty);
}
}
class Program
{
static void Main()
{
TestClass tc = new TestClass();
tc.Test += tc_Test;
tc.Test += tc_Test;
tc.OnTest();
Console.In.ReadLine();
}
static void tc_Test(object sender, EventArgs e)
{
Console.Out.WriteLine("tc_Test called");
}
}
}
Output:
tc_Test called
(ie. only once)
Microsoft's Reactive Extensions (Rx) framework can also be used to do "subscribe only once".
Given a mouse event foo.Clicked, here's how to subscribe and receive only a single invocation:
Observable.FromEvent<MouseEventArgs>(foo, nameof(foo.Clicked))
.Take(1)
.Subscribe(MyHandler);
...
private void MyHandler(IEvent<MouseEventArgs> eventInfo)
{
// This will be called just once!
var sender = eventInfo.Sender;
var args = eventInfo.EventArgs;
}
In addition to providing "subscribe once" functionality, the RX approach offers the ability to compose events together or filter events. It's quite nifty.
Create an Action instead of an event. Your class may look like:
public class MyClass
{
// sender arguments <----- Use this action instead of an event
public Action<object, EventArgs> OnSomeEventOccured;
public void SomeMethod()
{
if(OnSomeEventOccured!=null)
OnSomeEventOccured(this, null);
}
}
have your singleton object check it's list of who it notifies and only call once if duplicated. Alternatively if possible reject event attachment request.
In silverlight you need to say e.Handled = true; in the event code.
void image_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
e.Handled = true; //this fixes the double event fire problem.
string name = (e.OriginalSource as Image).Tag.ToString();
DoSomething(name);
}
Please tick me if this helps.

Categories