1

我正在编写一个框架,其中一个功能涉及远程处理事件(我认为现在不相关的细节)。但是,需要的是能够在给定目标对象引用和事件名称的情况下将事件处理程序挂钩到任何事件。

处理事件的方法将编组/以其他方式将参数代理到某些处理程序代码,然后将返回类型转换为事件处理程序的返回类型。实际上,它包装了处理程序。

我相信由于事件处理程序可能需要具有任意数量的任何类型的参数,处理按需挂钩事件的请求的唯一方法是使用反射/发射(代码生成)来构建自定义代理方法。我发布这个问题是为了检查这个假设,看看是否有人有任何其他/更简洁的想法。

目前,我创建了一个DynamicMethod,然后做这种事情。它几乎可以工作,但是这个动态代理方法调用的包装器方法必须是静态的(声明非常多public static object GenericHandler(object[] parameters));我不想这样。所以我当前的任务是动态创建一个完整的类型,使用这个方法,还要一个字段来存储对象的实例来调用包装器。但是,这不是重点(我认为)——我想检查我关于必须创建动态代码的假设是否正确。但是,对于参考:

        // obj = target object, eventName = event name
        var evtInfo = obj.GetType().GetEvent(eventName);

        var handlerType = evtInfo.EventHandlerType;

        var eventInvokeMethod = handlerType.GetMethod("Invoke");
        var paramTypes = eventInvokeMethod.GetParameters().Select(p => p.ParameterType).ToArray();
        var returnType = eventInvokeMethod.ReturnType;

        var handlerMethod = new DynamicMethod(
            "evtHandler_" + eventName,
            MethodAttributes.Static | MethodAttributes.Public,
            CallingConventions.Standard,
            returnType,
            paramTypes,
            typeof(my container class).Module,
            false);

        var il = handlerMethod.GetILGenerator();

        // locals: [0] = parameter array
        il.DeclareLocal(typeof(object[]));

        // create an appropriately-sized array objects, for the parameters
        il.Emit(OpCodes.Ldc_I4, (int)paramTypes.Count());
        il.Emit(OpCodes.Newarr, typeof(object));
        il.Emit(OpCodes.Stloc_0);

        for (int i = 0; i < paramTypes.Length; i++)
        {
            // for the array: load the parameter into the same index of the array
            il.Emit(OpCodes.Ldloc_0);
            il.Emit(OpCodes.Ldc_I4, i);
            il.Emit(OpCodes.Ldarg, i);
            if (!paramTypes[i].IsClass)
            {
                // box the value first..
                il.Emit(OpCodes.Box, paramTypes[i]);
            }
            il.Emit(OpCodes.Stelem_Ref);
        }

        // call our generic handler with the array of parameters, then convert the return
        // value to the target type via unboxing or a cast
        il.Emit(OpCodes.Ldloc_0);
        il.Emit(OpCodes.Call, wrapper.GetMethodInfo());
        if (!returnType.IsClass)
        {
            il.Emit(OpCodes.Unbox_Any, returnType);
        }
        else
        {
            il.Emit(OpCodes.Castclass, returnType);
        }
        il.Emit(OpCodes.Ret);

如果没有响应并且我得到了上述理论与包装器类型的工作,我将发布更新的代码.. 但如果他们在那里,我很想听听这种方法的替代品。

4

1 回答 1

0

有必要实现(并改进)上述代码。使用动态生成的程序集、类型和方法,我可以将任何触发的事件代理到通用object HandleEvent(object[] parameters)方法。

于 2012-11-30T23:35:27.577 回答