我正在编写一个框架,其中一个功能涉及远程处理事件(我认为其中的细节现在不相关)。但是,在给定目标对象引用和事件名称的情况下,需要将事件处理程序挂钩到任何事件。
处理事件的方法将封送/以其他方式将参数代理到某些处理程序代码,然后将返回类型强制转换为事件处理程序的返回类型。实际上,它包装了处理程序。
我认为,由于事件处理程序可能需要具有任意类型的任意数量的参数,因此处理按需挂钩事件的请求的唯一方法是使用reflection / emit(代码生成) )构建自定义代理方法。我发布这个问题来检查这个假设,看看是否有人有任何其他/更好的想法。
目前,我创建了一个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);
如果没有回复,我得到了包装类型工作的上述理论,我会发布更新的代码..但是如果他们在那里,我很乐意听到这种方法的替代方法。
答案 0 :(得分:0)
有必要实现(并改进)上述代码。使用动态生成的程序集,类型和方法,我可以将触发的任何事件代理为常规object HandleEvent(object[] parameters)
方法。