Does an event need to have at least one handler? - c#

Why event needs to have at least one handler?
I created custom event for my Control and somewhere inside of code of my control, I call this event:
this.MyCustomEvent(this, someArgs);
it throws a NullReferenceException if there is no handler subscribed to it.
When I added a single handler in control's constructor, everything works fine:
this.MyCustomEvent += myCutomEventHandler;
void myCustomEventHandler(object sender, EventArgs e)
{ /* do nothing */ }
Is this normal or maybe I'm doing something wrong?
Shouldn't it check automatically if there are any handlers subscribed? It's a little dumb, IMHO.

I recommend you to have an extremely useful extension method:
public static void Raise<T>(this EventHandler<T> eventHandler, object sender, T e) where T : EventArgs
{
if (eventHandler != null)
{
eventHandler(sender, e);
}
}
which will do the check for you.
Usage:
MyCustomEvent.Raise(this, EventArgs.Empty);

Note that delegates are reference types, and their default value is null.
The solution proposed by others, i.e. to check for null before firing the event, is not thread-safe because listeners may unsubscribe from the event between the null check and the firing of the event.
I have seen solutions that involve copying the delegate to a local variable, and checking it for null before firing, such as
EventHandler myCustomEventCopy = MyCustomEvent;
if (myCustomEventCopy != null)
{
myCustomEventCopy (this, someArgs);
}
But this has a race-condition, i.e. handlers may fire even after they have unsubscribed from the event, which may corrupt the state of the application.
One solution that handles both problems is to initialize events to a blank handler, e.g.
public event EventHandler MyCustomEvent = delegate { };
and then fire them off without any checks, e.g.
MyCustomEvent(this, someArgs);
Edit: As others have pointed out, this is a complex issue.
http://blogs.msdn.com/b/ericlippert/archive/2009/04/29/events-and-races.aspx
Lippert points out that completely removing the "handler is fired after deregistration" problem requires that the handlers themselves are written in a robust manner.

An event at the bottom is MulticastDelegate, which is null if there is no method in the invocation list. Usually, you use a RaiseEvent() method to call an event, the pattern looks like the following:
public void RaiseEvent()
{
var handler = MyEvent;
if(handler != null)
handler(this, new EventArgs());
}
As you assign the event to a variable, it is threadsafe. You can miss a removed or added method though, which was added between the atomic operations (assignment -> null check -> invocation).

This is normal behaviour. The conventional pattern for throwing an event in .NET is to have a method called OnMyCustomEvent that you use to throw the event, like so:
protected void OnMyCustomEvent(MyCustomEventArgs e)
{
EventHandler<MyCustomEventArgs> threadSafeCopy = MyCustomEvent;
if (threadSafeCopy != null)
threadSafeCopy(this, e);
}
public event EventHandler<MyCustomEventArgs> MyCustomEvent;
Then from your code, you would call this.OnMyCustomEvent(someArgs) instead.

This is the normal behavior. To avoid this always test if there's an event subscriber before calling it:
if (MyCustomEvent != null)
{
MyCustomEvent(this, someArgs);
}

There is the "standard" approach of copying the reference and then checking for null (the value of the reference if no handlers are attached)—as given by other answers:
public EventHandler<MyEventArgs> MyEvent;
protected virtual OnMyEvent(MyEventArgs args) {
var copy = MyEvent;
if (copy != null) {
copy(this, args);
}
}
This works because, in part, MulticastDelegate instances are immutable.
There is another approach: the Null Object Pattern:
public EventHandler<MyEventArgs> MyEvent;
// In constructor:
MyEvent += (s,e) => {}; // No op, so it is always initialised
And there is no need to take a copy or check for null because it won't be. This works because there is no Clear method on an event.

Yes, you need to check for null. In fact, there's a right way to do it:
var myEvent = MyCustomEvent;
if (myEvent != null)
myEvent(this, someArgs);
This is the official right way because it avoids a possible race condition when the event is changed after the null check but before the call.

Related

Equivalent of VB's custom RaiseEvent blocks in C#?

(I know the title sounds easy, but hold on—this probably isn't the question you think it is.)
In VB.NET I was able to write custom events. For an example, I had a separate thread that would periodically raise an event and on that event the GUI would need to be updated. I didn't want the busy thread to bother with UI calculations and I didn't want to put Me.Invoke(Sub() ...) in the event handler since it was also called from the GUI thread.
I came up with this very useful bit of code. The GUI thread would set EventSyncInvoke = Me (the main form). The thread could then simply raise the event TestEvent as usual, no special code, and it would be seamlessly executed on the GUI thread:
Private TestEventDelegate As EventHandler
Public EventSyncInvoke As System.ComponentModel.ISynchronizeInvoke
Public Custom Event TestEvent As EventHandler
AddHandler(value As EventHandler)
TestEventDelegate = [Delegate].Combine(TestEventDelegate, value)
End AddHandler
RemoveHandler(value As EventHandler)
TestEventDelegate = [Delegate].Remove(TestEventDelegate, value)
End RemoveHandler
RaiseEvent(sender As Object, e As System.EventArgs)
If EventSyncInvoke IsNot Nothing Then
EventSyncInvoke.Invoke(TestEventDelegate, {sender, e})
Else
TestEventDelegate.Invoke({sender, e})
End If
End RaiseEvent
End Event
Now in C# I can do this much:
public event EventHandler TestEvent
add
{
testEventDelegate = (EventHandler)Delegate.Combine(testEventDelegate, value);
}
remove
{
testEventDelegate = (EventHandler)Delegate.Remove(testEventDelegate, value);
}
}
But where is the ability to do custom raising?
The other answers told me the fact that I couldn't do this directly in C#, but not the rationale behind why I can't and why I wouldn't want to. It took me a while to understand how C# events worked in comparison to VB.NET. So this explanation is for others who don't have a good grasp on this to start thinking along the right lines.
Honestly, I was so used to the boilerplate OnTestEvent format that I didn't quite like the idea of making it different from the rest of the helper methods. :-) But now that I understand the rationale, I see that it is actually the best place to put this stuff.
VB.NET allows you to hide the background details of calling the delegates with the RaiseEvent keyword. RaiseEvent calls either the event delegate or your custom RaiseEvent section for a custom event.
In C#, there is no RaiseEvent. Raising an event is basically no more than calling a delegate. No custom RaiseEvent sections can be seamlessly called when all you're doing to raise it is calling a delegate. So for C#, custom events are like skeletons, implementing add and remove for events but not implementing the ability to raise them. It's like having to replace all your RaiseEvent TestEvent(sender, e) with the code from the custom RaiseEvent section.
For a normal event, raising looks roughly like NormalEvent(sender, e). But as soon as you put in a custom add and remove, you must use whatever variable you used in the add and remove because the compiler isn't doing it anymore. It's like automatic properties in VB.NET: once you put in a getter and setter manually, you have to declare and handle your own local variable. So instead of TestEvent(sender, e), use testEventDelegate(sender, e). That's where you rerouted the event delegates.
I compared moving from VB.NET to C# with having to replace each of your RaiseEvents with your custom RaiseEvent code. A RaiseEvent code section is basically an event and a helper function rolled together. It's actually standard to only have one instance of a RaiseEvent in either VB.NET or C# inside a protected OnTestEvent method and call that method to raise the event. This allows any code with access to the protected (or private or public) OnTestEvent to raise the event. For what you want to do, just putting it in the method is easier, simpler and performs slightly better. This is best practice.
Now if you really want to want (or need) somehow to mimic VB.NET's RaiseEvent nitty-gritty-hiding call SomeDelegate(sender, e) and have the magic happen, you can simply hide the nitty-gritty inside a second delegate:
NiceTestEvent = (sender, e) => eventSyncInvoke.Invoke(testEventDelegate, new object[] { sender, e });
Now you can call NiceTestEvent(sender, e). You won't be able to call TestEvent(sender, e) though. TestEvent is only for outside code to add and remove through, as Visual Studio will tell you.
In C#, there isn't any RaiseEvent block. You would do the same thing by creating a method for raising your event.
Here is a working example. In the C# version, you do not even need to use the add and remove block -- you can use the default implementation for that and just create a custom raise method that raises your event.
Below is a working program (the form is just a Windows Forms form with a single button on it).
// Here is your event-raising class
using System;
using System.ComponentModel;
namespace ClassLibrary1
{
public class Class1
{
public ISynchronizeInvoke EventSyncInvoke { get; set; }
public event EventHandler TestEvent;
private void RaiseTestEvent(EventArgs e)
{
// Take a local copy -- this is for thread safety. If an unsubscribe on another thread
// causes TestEvent to become null, this will protect you from a null reference exception.
// (The event will be raised to all subscribers as of the point in time that this line executes.)
EventHandler testEvent = this.TestEvent;
// Check for no subscribers
if (testEvent == null)
return;
if (EventSyncInvoke == null)
testEvent(this, e);
else
EventSyncInvoke.Invoke(testEvent, new object[] {this, e});
}
public void Test()
{
RaiseTestEvent(EventArgs.Empty);
}
}
}
// Here is a form that tests it -- if you run it, you will see that the event is marshalled back to
// the main thread, as desired.
using System;
using System.Threading;
using System.Windows.Forms;
namespace ClassLibrary1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.TestClass = new Class1();
this.TestClass.EventSyncInvoke = this;
this.TestClass.TestEvent += new EventHandler(TestClass_TestEvent);
Thread.CurrentThread.Name = "Main";
}
void TestClass_TestEvent(object sender, EventArgs e)
{
MessageBox.Show(this, string.Format("Event. Thread: {0} Id: {1}", Thread.CurrentThread.Name, Thread.CurrentThread.ManagedThreadId));
}
private Class1 TestClass;
private void button1_Click(object sender, EventArgs e)
{
// You can test with an "old fashioned" thread, or the TPL.
var t = new Thread(() => this.TestClass.Test());
t.Start();
//Task.Factory.StartNew(() => this.TestClass.Test());
}
}
}
You simply can't. But since events can be raised only from inside the type that declares them, you can create a helper method that executes your specific raising code. And then just make sure you don't raise the event directly outside that method.
AFAIK custom event raising as in VB.NET does not exist in C#. However, you could wrap the actual event handler delegates (passed to add as value) in a lambda and subscribe that lambda to the event instead of the original delegate:
add
{
testEventDelegate = Delegate.Combine(testEventDelegate, (s, e) => { ... } )
}
(Above code untested, syntax might be slightly off. I'll fix it as soon as I can test it.)
Crude, but working example:
The following is a concrete example of the above. I am not convinced myself that the following is good, solid code, nor that it would work in all circumstances (such as multi-threading etc.)... nevertheless, here it is:
class Foo
{
public Foo(SynchronizationContext context)
{
this.context = context ?? new SynchronizationContext();
this.someEventHandlers = new Dictionary<EventHandler, EventHandler>();
}
private readonly SynchronizationContext context;
// ^ could also use ISynchronizeInvoke; I chose SynchronizationContext
// for this example because it is independent from, but compatible with,
// Windows Forms.
public event EventHandler SomeEvent
{
add
{
EventHandler wrappedHandler =
(object s, EventArgs e) =>
{
context.Send(delegate { value(s, e); }, null);
// ^ here is where you'd call ISynchronizeInvoke.Invoke().
};
someEvent += wrappedHandler;
someEventHandlers[value] = wrappedHandler;
}
remove
{
if (someEventHandlers.ContainsKey(value))
{
someEvent -= someEventHandlers[value];
someEventHandlers.Remove(value);
}
}
}
private EventHandler someEvent = delegate {};
private Dictionary<EventHandler, EventHandler> someEventHandlers;
public void RaiseSomeEvent()
{
someEvent(this, EventArgs.Empty);
// if this is actually the only place where you'd invoke the event,
// then you'd have far less overhead if you moved the ISynchronize-
// Invoke.Invoke() here and forgot about all the wrapping above...!
}
}
(Note that I've used the C# 2 anonymous delegate {} syntax for brevity.)

Invoke of an EventHandler

I have the following EventHandler:
private EventHandler<MyEventArgs> _myEventHandler;
public event EventHandler<MyEventArgs> MyEvent
{
add { _myEventHandler += value; }
remove { _myEventHandler -= value; }
}
Could somebody explain the difference between the following snippets?
Snippet EventHandler (A):
//Snippet A:
if (_myEventHandler != null)
{
_myEventHandler(new MyEventArgs());
}
Snippet BeginInvoke (B):
//Snippet B:
if (_myEventHandler != null)
{
_myEventHandler.BeginInvoke(new MyEventArgs(), ar =>
{
var del = (EventHandler<MyEventArgs>)ar.AsyncState;
del.EndInvoke(ar);
}, _myEventHandler);
}
For clarification: What's the difference between invoking an EventHandler "just as it is" and using BeginInvoke?
The BeginInvoke approach is async, meaning that it is raised on a different thread. This can be dangerous if people don't expect it, and is pretty rare for events - but it can be useful.
Also, note that strictly speaking you should snapshot the event handler value - this is especially true if (via Begin*) you are dealing with threads.
var tmp = _myEventHandler;
if(tmp != null) {
tmp(sender, args);
}
Also - note that your event subscription itself is not thread-safe; again, this only matters if you are dealing with multi-threading, but the inbuilt field-like event is thread-safe:
public event EventHandler<MyEventArgs> MyEvent; // <===== done; nothing more
The issues avoided here are:
with the snapshot, we avoid the risk of the last subscriber unsubscribing between the null-check and the invoke (it does mean they might get an event they didn't expect, but it means we don't kill the raising thread)
with the field-like event change we avoid the risk of losing subscriptions / unsubscriptions when two threads are doing this at the same time
BeginInvoke() call immediatelly returns control to the calling thread and run a delegate in a separate thread from the ThreadPool, so this will be some kind of asynchronous execution.

Should cancellable event args be passed to all handlers, if the first handler cancels it?

I've got an extension method that raises cancellable events, returning a bool if they're cancelled:
public static bool RaiseCancel<T>(this EventHandler<T> ev, object sender, T e) where T : CancelEventArgs
{
if (ev == null)
{
return false;
}
foreach (Delegate del in ev.GetInvocationList())
{
try
{
ISynchronizeInvoke invoke = del.Target as ISynchronizeInvoke;
if (invoke != null && invoke.InvokeRequired)
{
invoke.Invoke(del, new[] { sender, e });
}
else
{
del.DynamicInvoke(sender, e);
}
}
catch (TargetInvocationException ex)
{
throw ex.InnerException;
}
// if (e.Cancel) return true;
}
return e.Cancel;
}
However, I can't help thinking it should return immediately when a handler cancels it for the sake of efficiency, rather than continue to call the remaining handlers. As far as I'm aware, no handler of a cancellable event should EVER take any action other than to set the Cancel property to true. That being the case, what's the point asking more handlers to make a decision that's already been made? On the other hand, it seems wrong NOT to call an event handler when it happens if an object is listening for the event.
Should I uncomment that if statement (and replace the return at the end of the method with return false;) or not?
EDIT: I suppose if you're going to continue to call handlers, should I allow handlers themselves to make the decision (i.e., they can have if (e.Cancel) return; at the beginning of the handler) if they want?
NOTE: what I describe here is only what I think makes sense. It might not be implemented this way in the .NET framework (see João Angelo's comment below)
Take an example: the FormClosing event. If a handler cancels this event, the form is not going to be closed, so it doesn't make sense to notify the other handlers that the form is being closed.
In the more general case, if you call the other handlers after e.Cancel is set to true, you're notifying them of an something that isn't happening anymore...
So in my opinion you should stop invoking the handlers as soon as e.Cancel is set to true.

Why is this event declared with an anonymous delegate?

I have seen people define their events like this:
public event EventHandler<EventArgs> MyEvent = delegate{};
Can somebody explain how this is different from defining it without it? Is it to avoid checking for null when raising the event?
You got it - adding the empty delegate lets you avoid this:
public void DoSomething() {
if (MyEvent != null) // Unnecessary!
MyEvent(this, "foo");
}
This declaration ensures that MyEvent is never null, removing the tedious and error-prone task of having to check for null every time, at the cost of executing an extra empty delegate every time the event is fired.

C# Delegates and Events design help

I have some code in my project that saves an object to the database, once this is done I want it to call a series of other methods.
I was thinking about allowing other methods to subscribe to this event so I can add more as I need to. The idea I had for this was to create an array of Delegates allowing other methods to register, then when the object had been saved it could loop through the delegates and call each one.
Would this be bad practise or is there a better way of doing this?
Thanks
Event delegates are multicast, which means that they can hold references to more than one event handling method - see the MSDN documentation for Delegate and MulticastDelegate.
The syntax for subscribing to an event gives a clue:
MyEvent += MyHandler; // subscribe to an event
MyEvent -= MyHandler; // unsubscribe from an event
You can subscribe as many delegates as you want to a single event. Under the hood .Net keeps these as an ordered collection anyway.
The standard pattern for this is:
//in your class
public EventHandler<MyEvtArgs> MyEvent;
protected void OnMyEvent ( MyEvtArgs args ) {
if(MyEvent != null) //make sure there is at least 1 subscriber
MyEvent(this, args);
}
Then to call this:
var myInstance = new MyClass();
// all of these can convert to EventHandler<MyEvtArgs> (object, MyEvtArgs)
myInstance.MyEvent += (sender, e) => { /* do something 1 */ };
myInstance.MyEvent += (sender, e) => { /* do something 2 */ };
myInstance.MyEvent += localMethod;
Now when your protected OnMyEvent method is called inside your class all of these events will fire - in order.
You can also remove items from this collection:
myInstance.MyEvent -= localMethod;
You don't need an array. Just let anyone subscribe to one.
You can use a normal event for this. The runtime will handle looping over all fields.
public event EventHandler<EventArgs> WritingToDatabaseFinished;
protected void OnWritingToDatabaseFinished(EventArgs args)
{
EventHandler<EvetnArgs> handler = WritingToDatabaseFinished;
if (handler != null)
{
handler(this, args);
}
}
Your code calls
OnWritingToDatabaseFinished(args);
All methods that want to be informed have to register to the event:
WritingToDatabaseFinished += new EventHandler<EventArgs>(handlermethod);
Every handler that has been registered in the above way will be called when you call OnWritingToDatabaseFinished.
All you need is a multicast delegate. You don't need an array at all. You use += to add a reference to the delegate, and a -= to remove the reference.
I would recommend that you look at using a weak event handler instead. Take a look at this link to see why you'd use a weak event instead of a weak delegate.
Delegates are already multicast, so no need for a delegate array. Now, the recommended way of adding event support to your class is:
Add a public delegate (this will be your event handler)
public delegate void DatabaseEventHandler(object sender, DatabaseEventArgs e);
Add a public event, of your delegate type.
public event DatabaseEventHandler DatabaseDone;
Now, the event should send 2 parameters. The sender (this, usually), and the EventArgs. You should create a new class from System.EventArgs, and send the appropriate information within that class.

Categories

Resources