tags:

views:

329

answers:

3

I need to copy the subscribers of one event to another event. Can I get the subscribers of an event (like MyEvent[0] returning a delegate)?

If this is not possible I would use the add accessor to add the delegates to a list. Would that be the best solution?

+1  A: 

Update (thank to commenters): delegate immuntability means that cloning achieves nothing over an assignment.

When one writes:

myDelegate += AHandler

a completely new delegate instance is created and assigned to myDelegate.

Therefore, the code below would work exactly the same without the Clone call.


MulticastDelegate (the underlying type) has a Clone method.

To be able to get to the underlying delegate you might need to avoid the usual helper that the event keyword generates, and manage things directly (custom add and remove accessors).

To show this:

    class Program {
        public delegate void MyDelegate(string name);

        public event MyDelegate EventOne;

        public void HandlerOne(string name) {
            Console.WriteLine("This is handler one: {0}", name);
        }
        public void HandlerTwo(string name) {
            Console.WriteLine("This is handler two: {0}", name);
        }
        public void HandlerThree(string name) {
            Console.WriteLine("This is handler three: {0}", name);
        }

        public void Run() {
            EventOne += HandlerOne;
            EventOne += HandlerTwo;
            Console.WriteLine("Before clone");
            EventOne("EventOne");

            MyDelegate eventTwo = (MyDelegate)EventOne.Clone();
            MyDelegate eventTwo = EventOne;
            Console.WriteLine("After clonecopy");
            EventOne("EventOne");
            eventTwo("eventTwo");

            Console.WriteLine("Change event one to show it is different");
            EventOne += HandlerThree;
            EventOne("EventOne");
            eventTwo("eventTwo");
        }

        static void Main(string[] args) {
            (new Program()).Run();
        }
    }
Richard
Clone itself is relatively unimportant - delegates are immutable, so you can just copy the delegate reference.
Jon Skeet
Unless, as in the sample, you want to then modify the original or copy independently.
Richard
Richard - no, that would work **identically** without the Clone() step.
Marc Gravell
Also, re "To be able to get to the underlying delegate" - the C# spec dictates that for field-like events (the simple ones), then inside the class any reference to the event-name **is** talking to the delegate field.
Marc Gravell
Marc: of course. (Not enough coffee yet). (And easy to forget that += is .NET is not the shortcut in other languages).
Richard
+3  A: 

If the event is one published by another class, you can't - at least, not reliably. While we often think of an event as being just a delegate variable, it's actually just a pair of methods: add and remove (or subscribe and unsubscribe).

If it's your own code that's publishing the event, it's easy - you can make the add/remove accessors do whatever you like.

Have a look at my article on events and see if that helps you. If not, please give more details about what you want to do, specifying which bits of code you're able to modify and which you aren't.

Jon Skeet
+2  A: 

C# events/delegates are multicast, so the delegate is itself a list. From within the class, to get individual callers, you can use:

if(field != null) { // or the event-name for field-like events
    // or your own event-type in place of EventHandler
    foreach(EventHandler subscriber in field.GetInvocationList())
    {
        // etc
    }
}

However, to assign all at once, just use += or direct assignment:

SomeType other = ...
other.SomeEvent += localEvent;
Marc Gravell
Thanks for pointing that out. That's best for events in my own code.