0

I'm trying to create a reusable method for a more complicated event execution. I can't get it to compile or run with framework events that don't follow the EventHandler<Type> pattern. I would like to avoid reflection if possible as it will be a heavily used event.

I've created a test console app below which illustrates the problem:

using System;
using System.Collections.Specialized;

namespace CallEventsViaMethod
{
    public class TestEventArgs : EventArgs { }

    class Program
    {
        static void Main(string[] args)
        {
            MyProgram program = new MyProgram();
            program.Go();
            Console.ReadKey(false);
        }
    }

    public class MyProgram
    {
        public event EventHandler<TestEventArgs> TestEvent;
        public event NotifyCollectionChangedEventHandler CollectionChangedEvent;

        public void Go()
        {
            TestEvent += new EventHandler<TestEventArgs>(MyProgram_TestEvent);
            CollectionChangedEvent += new NotifyCollectionChangedEventHandler(MyProgram_CollectionChangedEvent);

            // Want a reusable method I can use to conditionally execute any event
            GeneralEventExecutor.Execute<TestEventArgs>(TestEvent, new Object(), new TestEventArgs());
            GeneralEventExecutor.Execute<NotifyCollectionChangedEventArgs>(TestEvent, new Object(), new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
        }

        void MyProgram_TestEvent(object arg1, TestEventArgs arg2)
        {
            Console.WriteLine("Custom event ran");
        }

        void MyProgram_CollectionChangedEvent(object sender, NotifyCollectionChangedEventArgs e)
        {
            Console.WriteLine("NotifyCollectionChangedEventHandler event ran");
        }
    }

    public static class GeneralEventExecutor
    {
        public static void Execute<T>(EventHandler<T> eventToRaise, object sender, T eventArgs) where T : EventArgs
        {
            if (eventToRaise == null)
                return;

            Delegate[] registeredEventHandlers = eventToRaise.GetInvocationList();

            foreach (EventHandler<T> eventHandler in registeredEventHandlers)
            {
                object target = eventHandler.Target; // Need access to the Target property

                // * Code deciding if should invoke the event handler *

                eventHandler.Invoke(sender, eventArgs);
            }
        }
    }
}

Error messages are:

error CS1502: The best overloaded method match for 'CallEventsViaMethod.GeneralEventExecutor.Execute(System.EventHandler, object, System.Collections.Specialized.NotifyCollectionChangedEventArgs)' has some invalid arguments

error CS1503: Argument 1: cannot convert from 'System.EventHandler' to 'System.EventHandler'

I understand why I'm getting the error, but can't figure out a way round it.

Lee
  • 1,591
  • 1
  • 14
  • 28
  • Aren't you reinveinting the Event Aggregator? – Wiktor Zychla May 26 '13 at 22:39
  • What the Execute method is doing in my production code is either Invoking the event normally, or invoking it via dispatcher, I was just trying to keep the code simple. I don't think the Event Aggregator would suffice in this case? – Lee May 26 '13 at 22:44
  • Looks like it can't done without reflection: http://stackoverflow.com/questions/8407886/pass-event-as-parameter-to-a-method – Lee May 27 '13 at 00:51

1 Answers1

0

Replace your your generic Execute<T> as below

public static void Execute<T>(Delegate eventToRaise, object sender, T eventArgs) where T:EventArgs
        {
            if (eventToRaise == null)
                return;

            Delegate[] registeredEventHandlers = eventToRaise.GetInvocationList();

            foreach (Delegate eventHandler in registeredEventHandlers)
            {
                object target = eventHandler.Target; // Need access to the Target property for conditions

                // * Code deciding if should invoke the event handler *

                eventHandler.DynamicInvoke(sender, eventArgs);
            }
        }
S.N
  • 4,910
  • 5
  • 31
  • 51
  • Get an error at runtime on line eventHandler.Invoke... "Delegate 'System.EventHandler' has some invalid arguments" – Lee May 26 '13 at 22:49
  • Check now with DynamicInvoke as above – S.N May 26 '13 at 22:57
  • Don't really understand why, but I get: Object of type 'System.Collections.Specialized.NotifyCollectionChangedEventArgs' cannot be converted to type 'CallEventsViaMethod.TestEventArgs'. – Lee May 26 '13 at 23:43