Исключение из DynamicMethod.CreateDelegate, почти идентичный пример MSDN - PullRequest
3 голосов
/ 16 июня 2011

Когда я вызываю 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

EDIT: Событие, которое я пытаюсь связать с:

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

1 Ответ

3 голосов
/ 16 июня 2011

Большинство событий ничего не возвращают - на самом деле вы утверждаете , что у него нет возвращаемого типа.Затем вы объявляете свой пользовательский метод (handler) как возвращающий int и пытаетесь связать его с делегатом, который не возвращает int.Это не сработает.

Также;ваш стек недопустим для возврата целого числа, так как вы «выталкиваете» результат.

т.е. я создал тест с

public event EventHandler SomeEvent;

и привязал его к нему;тогда вот:

Delegate dEmitted = handler.CreateDelegate(tDelegate);

вы обнаружите, что tDelegate - это EventHandler.Это не соответствует handler, что возвращает int.


Re the stack (комментарии);рассмотрим:

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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...