tags:

views:

265

answers:

6

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

+1  A: 

You don't need an array. Just let anyone subscribe to one.

Preet Sangha
Not that up on Delegates and not sure how this would work. I use code like "public delegate void Del(string message); Del handler = DelegateMethod;" how would more than one method subscribe to this delegate?
Gavin Draper
see @PVit's anwer
Preet Sangha
+2  A: 

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
Vinay Sajip
+1  A: 

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;
Keith
As an aside, I have been defaulting my handler for a while now to avoid the null check, i.e., public event EventHandler MyEvent = delegate { };
Ed Swangren
Yeah - I prefer not to do that as it has a very slight overhead over the null check. Really the difference is so tiny that it just comes down to whatever works best in your code.
Keith
Using the if(MyEvent != null) syntax is not thread safe and can cause a race condition.
Repo Man
@Repo Man - how come? If that isn't thread safe (and as I haven't locked here it isn't) and someone removes a subscriber while I'm going through wouldn't that just result in a `NullReferenceException`? Why would it race? In MS's own code they use this pattern all over the place. Also - is there a better way to test for a subscriber then?
Keith
A: 

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.

PVitt
small niggle on c# 3 you can say WritingToDatabaseFinished += handlermethod;
Preet Sangha
Thanks. Nice syntactic sugar I wasn't aware of.
PVitt
A: 

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.

Pete OHanlon
A: 

Delegates are already multicast, so no need for a delegate array. Now, the recommended way of adding event support to your class is:

  1. Add a public delegate (this will be your event handler)

public delegate void DatabaseEventHandler(object sender, DatabaseEventArgs e);

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

Rodrigo Garcia