DynamicMethod出现异常.CreateDelegate,几乎完全相同的MSDN示例

本文关键字:示例 MSDN 异常 CreateDelegate DynamicMethod | 更新日期: 2023-09-27 17:59:21

当我调用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);
    }
}

DynamicMethod出现异常.CreateDelegate,几乎完全相同的MSDN示例

大多数事件都不返回任何内容-事实上,您断言它没有返回类型。然后,您将自定义方法(handler)声明为返回int,并尝试将其绑定到不返回int的委托。这将不起作用。

此外;堆栈对于返回int无效,因为您"弹出"了结果。

即我用创建了一个测试

public event EventHandler SomeEvent;

并与之绑定;那么这里:

Delegate dEmitted = handler.CreateDelegate(tDelegate);

你会发现tDelegate就是EventHandler。这与返回inthandler不匹配。


重新堆叠(注释);考虑:

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);