当我调用CreateDelegate(delegateType)时,我得到一个System.ArgumentException
,根据MSDN,这是因为delegateType的参数数量错误或参数类型错误。
奇怪的部分是我使用的代码几乎都是从MSDN复制的。我的整体功能:
public static void AssertRaisesEvent(Action action, object obj, string eventName, NumberOfTimes numberOfTimesRaised)
{
eventCounter = 0;
EventInfo eventInfo = obj.GetType().GetEvent(eventName);
Type tDelegate = eventInfo.EventHandlerType;
Type returnType = GetDelegateReturnType(tDelegate);
if (returnType != typeof(void))
throw new ApplicationException("Delegate has a return type.");
var handler =
new DynamicMethod("CompletedHandler",
typeof(int),
GetDelegateParameterTypes(tDelegate),
obj.GetType());
// Generate a method body. This method loads a string, calls
// the Show method overload that takes a string, pops the
// return value off the stack (because the handler has no
// return type), and returns.
//
ILGenerator ilgen = handler.GetILGenerator();
FieldInfo counterFieldInfo = typeof (AssertionHelpers).GetField("eventCounter",
BindingFlags.NonPublic | BindingFlags.Static);
ilgen.Emit(OpCodes.Ldfld, counterFieldInfo);
ilgen.Emit(OpCodes.Ldc_I4, 1);
ilgen.Emit(OpCodes.Add);
ilgen.Emit(OpCodes.Pop);
ilgen.Emit(OpCodes.Ret);
// Complete the dynamic method by calling its CreateDelegate
// method. Use the "add" accessor to add the delegate to
// the invocation list for the event.
//
var delParams = GetDelegateParameterTypes(tDelegate);
var handlerParams = handler.GetParameters();
Delegate dEmitted = handler.CreateDelegate(tDelegate);
eventInfo.GetAddMethod().Invoke(obj, new Object[] { dEmitted });
...
正如你所看到的,评论甚至存在。你也可以看到我有delParams和handlerParams变量,它们具有相同数量的相同类型的参数。
这里发生了什么?
MSDN:http://msdn.microsoft.com/en-us/library/ms228976.aspx
编辑: 我试图绑定到的事件:
private NullTransaction transaction;
public delegate void CompletedEventHandler(object testParam);
internal class NullTransaction : ITransaction
{
public event CompletedEventHandler Completed;
public void Dispose()
{
// no implementation
}
public void Complete()
{
// no implementation
if(Completed != null)
Completed.Invoke(this);
}
}
答案 0 :(得分:3)
大多数事件都没有返回任何内容 - 实际上你断言它没有返回类型。然后,将自定义方法(handler
)声明为返回int
,并尝试将其绑定到不返回int的委托。这不起作用。
也;你的堆栈对于返回int是无效的,因为你“弹出”了结果。
即。我用
创建了一个测试public event EventHandler SomeEvent;
并受其约束;那么就在这里:
Delegate dEmitted = handler.CreateDelegate(tDelegate);
您会发现tDelegate
是EventHandler
。这与handler
不匹配,后者返回int
。
重新堆叠(评论);考虑:
ilgen.Emit(OpCodes.Ldfld, counterFieldInfo); <=== should be ldsfld, by the way
ilgen.Emit(OpCodes.Ldc_I4, 1); // stack is now [counter] [1]
ilgen.Emit(OpCodes.Add); // stack is now [counter + 1]
ilgen.Emit(OpCodes.Pop); // stack is now empty
ilgen.Emit(OpCodes.Ret); // return
你已经加载了两个值,将它们添加起来,抛出结果,然后返回。但是你还没有归还你声称的int
- 这将无法通过IL检查。
如果你改变:
var handler =
new DynamicMethod("CompletedHandler",
null,
GetDelegateParameterTypes(tDelegate),
obj.GetType());
和
ilgen.Emit(OpCodes.Ldsfld, counterFieldInfo);
ilgen.Emit(OpCodes.Ldc_I4_1);
ilgen.Emit(OpCodes.Add);
ilgen.Emit(OpCodes.Stsfld, counterFieldInfo);
ilgen.Emit(OpCodes.Ret);
那么它可能会按你的意愿运作。
也;这更简单:
Delegate dEmitted = handler.CreateDelegate(tDelegate);
eventInfo.AddEventHandler(obj, dEmitted);