Generic delegate type for handling any event

I have a function that receives two parameters - an object and an EventInfo structure that defines an event on this object. I need to block this function until the specified event occurs. The problem is how to add a delegate to the specified event when the handler type can be anything? Please note that I do not care about the parameters of this resulting event call, I just need to catch the fact that it is raised.

I already tried to use EventInfo.AddEventHandler to add a really generic delegate type ( EventHandler), but to no avail. I also tried the same thing, but using Activatorto create an instance of the type specified in the property EventInfo.EventHandlerType, but without joy.

Alternatively, if someone has a way to do this, given the object and event name on that object, then this will work too.

I am using C # and .NET 2.0.

Greetings

+5
source share
2 answers

A hint for a solution might be to use the MethodBuilder class . Using it, you can generate a method at runtime that matches the delegate that expects EventInfo.

An example based on this (many optimizations can be performed, but this works in most cases):

namespace AutoEventListener
{
    using System;
    using System.Linq;
    using System.Collections.Generic;
    using System.Reflection;
    using System.Reflection.Emit;

    public class EventExample
    {
        public static event EventHandler MyEvent;

        public void Test()
        {
            bool called;
            var eventInfo = GetType().GetEvent("MyEvent");
            EventFireNotifier.GenerateHandlerNorifier(eventInfo,
                callbackEventInfo =>
                    {
                        called = true;
                    });

            MyEvent(null, null);;
        }
    }

    public class EventFireNotifier
    {
        static private readonly Dictionary<int, EventInfo> eventsMap = new Dictionary<int, EventInfo>();
        static private readonly Dictionary<int, Action<EventInfo>> actionsMap = new Dictionary<int, Action<EventInfo>>();
        static private int lastIndexUsed;
        public static MethodInfo GenerateHandlerNorifier(EventInfo eventInfo, Action<EventInfo> action)
        {
            MethodInfo method = eventInfo.EventHandlerType.GetMethod("Invoke");
            AppDomain myDomain = AppDomain.CurrentDomain;
            var asmName = new AssemblyName(){Name = "HandlersDynamicAssembly"};

            AssemblyBuilder myAsmBuilder = myDomain.DefineDynamicAssembly(
                asmName,
                AssemblyBuilderAccess.RunAndSave);

            ModuleBuilder myModule = myAsmBuilder.DefineDynamicModule("DynamicHandlersModule");

            TypeBuilder typeBuilder = myModule.DefineType("EventHandlersContainer", TypeAttributes.Public);

            var eventIndex = ++lastIndexUsed;
            eventsMap.Add(eventIndex, eventInfo);
            actionsMap.Add(eventIndex, action);

            var handlerName = "HandlerNotifierMethod" + eventIndex;

            var parameterTypes = method.GetParameters().Select(info => info.ParameterType).ToArray();
            AddMethodDynamically(typeBuilder, handlerName, parameterTypes, method.ReturnType, eventIndex);

            Type type = typeBuilder.CreateType();

            MethodInfo notifier = type.GetMethod(handlerName);

            var handlerDelegate = Delegate.CreateDelegate(eventInfo.EventHandlerType, notifier);

            eventInfo.AddEventHandler(null, handlerDelegate);
            return notifier;
        }

        public static void AddMethodDynamically(TypeBuilder myTypeBld, string mthdName, Type[] mthdParams, Type returnType, int eventIndex)
        {
            MethodBuilder myMthdBld = myTypeBld.DefineMethod(
                                                 mthdName,
                                                 MethodAttributes.Public |
                                                 MethodAttributes.Static,
                                                 returnType,
                                                 mthdParams);

            ILGenerator generator = myMthdBld.GetILGenerator();

            generator.Emit(OpCodes.Ldc_I4, eventIndex);
            generator.EmitCall(OpCodes.Call, typeof(EventFireNotifier).GetMethod("Notifier"), null);
            generator.Emit(OpCodes.Ret);
        }

        public static void Notifier(int eventIndex)
        {
            var eventInfo = eventsMap[eventIndex];
            actionsMap[eventIndex].DynamicInvoke(eventInfo);
        }
    }
}

The EventFireNotifier class logs an EventInfo a Action event that is raised when the event fires.

Hope this helps.

+2
source

, , . , . .

someobject.someevent += delegate{ // do whatever;} 
0

All Articles