当我调用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);
}
}
大多数事件都不返回任何内容-事实上,您断言它没有返回类型。然后,您将自定义方法(handler
)声明为返回int
,并尝试将其绑定到不返回int的委托。这将不起作用。
此外;堆栈对于返回int无效,因为您"弹出"了结果。
即我用创建了一个测试
public event EventHandler SomeEvent;
并与之绑定;那么这里:
Delegate dEmitted = handler.CreateDelegate(tDelegate);
你会发现tDelegate
就是EventHandler
。这与返回int
的handler
不匹配。
重新堆叠(注释);考虑:
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);