美好的一天
我写了以下方法:
private void RegisterEvent(object targetObject, string eventName, string methodName)
{
EventInfo eventInfo = targetObject.GetType().GetEvent(eventName);
MethodInfo method = eventInfo.EventHandlerType.GetMethod("Invoke");
IEnumerable<Type> types = method.GetParameters().Select(param => param.ParameterType);
DynamicMethod dynamicMethod = new DynamicMethod(eventInfo.EventHandlerType.Name, typeof (void), types.ToArray(), typeof (QueryWindow));
MethodInfo methodInfo = typeof (QueryWindow).GetMethod(methodName, new[] { typeof (object) });
ILGenerator ilGenerator = dynamicMethod.GetILGenerator(256);
ilGenerator.Emit(OpCodes.Ldarg_1);
ilGenerator.EmitCall(OpCodes.Call, methodInfo, null);
dynamicMethod.DefineParameter(1, ParameterAttributes.In, "sender");
dynamicMethod.DefineParameter(2, ParameterAttributes.In, "e");
// Get an argument exception here
Delegate methodDelegate = dynamicMethod.CreateDelegate(eventInfo.EventHandlerType, this);
eventInfo.AddEventHandler(targetObject, methodDelegate);
}
我收到带有消息
的ArgumentException绑定到目标方法时出错。
在
行Delegate methodDelegate = dynamicMethod.CreateDelegate(eventInfo.EventHandlerType, this);
有人能指出我的错误吗?
提前致谢。
答案 0 :(得分:4)
dynamicMethod.CreateDelegate(eventInfo.EventHandlerType,this);
此参数不正确。它引用了您的类,即生成动态类型的类。当然,你需要 targetObject 。
答案 1 :(得分:1)
调用DynamicMethod.CreateDelegate
时,不应传递目标参数。
编辑:
我认为您还必须使第一个参数= 0,并相应地更改codegen。
答案 2 :(得分:1)
假设methodName
是QueryWindow
的静态方法,这应该有效:
private static void RegisterEvent(object targetObject, string eventName, string methodName)
{
var eventInfo = targetObject.GetType().GetEvent(eventName);
var method = eventInfo.EventHandlerType.GetMethod("Invoke");
var types = method.GetParameters().Select(param => param.ParameterType);
var methodInfo = typeof(QueryWindow).GetMethod(methodName, new[] { typeof(object) });
// replaced typeof(void) by null
var dynamicMethod = new DynamicMethod(eventInfo.EventHandlerType.Name, null, types.ToArray(), typeof(QueryWindow));
ILGenerator ilGenerator = dynamicMethod.GetILGenerator(256);
// Using Ldarg_0 to pass the sender to methodName ; Ldarg_1 to pass the event args
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.EmitCall(OpCodes.Call, methodInfo, null);
// Added return
ilGenerator.Emit(OpCodes.Ret);
// Removed parameter definition (implicit from DynamicMethod constructor)
// Removed the target argument
var methodDelegate = dynamicMethod.CreateDelegate(eventInfo.EventHandlerType);
eventInfo.AddEventHandler(targetObject, methodDelegate);
}
编辑:
由于您可以使用.NET 3.5,因此您应该创建表达式树。这是另一种解决方案:
public class QueryWindow
{
public void RegisterEvent(object targetObject, string eventName, string methodName)
{
var eventInfo = targetObject.GetType().GetEvent(eventName);
var sender = Expression.Parameter(typeof (object), "sender");
var e = Expression.Parameter(typeof (EventArgs), "e");
var body = Expression.Call(Expression.Constant(this), methodName, null, e);
var lambda = Expression.Lambda(eventInfo.EventHandlerType, body, sender, e);
eventInfo.AddEventHandler(targetObject, lambda.Compile() );
}
public void OnEvent(object o)
{
Console.WriteLine(o);
}
}
请注意OnEvent
方法不再是静态的。我还假设您尝试订阅的事件是遵循.NET约定的事件(sender + event args)。这样,我们可以利用逆变并始终传递一个类型的lambda:
(object sender, EventArgs e) => { /* */ }