Как я могу отправить вызов делегату, чей тип еще не закончен во время отправки? - PullRequest
3 голосов
/ 03 марта 2010

У меня проблемы с отправкой вызова делегату, чей тип еще не закончен во время отправки. Я уточню: я объявил следующий тип делегата:

// Delegate type. The 'firstArgument' will be 'this', i.e., this is an open
// instance method: the implicit argument is here given explicitly, in
// 'firstArgument'. (See link below for explanation on open instance delegates).
public delegate Object DirectReadAccessor<T>(T firstArgument);

И теперь я пытаюсь динамически (то есть с TypeBuilder) создать следующий класс:

public MyClass {

    // Array of delegates. T has been replaced with MyClass because the
    // argument will be 'this', which is of type MyClass.
    private static DirectReadAccessor<MyClass>[] directReadAccessors;

    // Method that looks up a delegate in the array of delegates and calls it
    // with 'this'.
    public Object DirectRead(int i) {
        directReadAccessors[i](this);
    }

    // Method that is called by the declaring type to pass an array with the
    // MethodInfo of some methods. MyClass then creates delegates for these
    // methods and stores them in the directReadAccessors array.
    public static void InitializeClass(MethodInfo[] directReadAccessorsMInfo) {
        int length = directReadAccessorsMInfo.Length;
        Type[] typeArguments = new Type[] { typeof(MyClass) };
        directReadAccessors = new DirectReadAccessor<MyClass>[length];
        // For each method in directReadAccessorsMInfo...
        for (int i = 0; i < length; i++) {
            // Create a delegate and store it in directReadAccessors.
            directReadAccessors[i] = (DirectReadAccessor<MyClass>)
                   Delegate.CreateDelegate(
                          DirectReadAccessor<MyClass>, // Type of the delegate.
                          null, // Specify null first argument so that it's
                                // *open* instance.
                          directReadAccessorsMInfo[i].MakeGenericMethod(typeArguments) // The method.
                    );
        }
    }

}

* на открытых экземплярах делегатов .

Это было сложно, потому что MyClass не существует, когда я пытаюсь объявить поле directReadAccessors, которое имеет тип DirectReadAccessor [], или когда я запускаю метод InitalizeClass, который снова использует MyClass, который не существует пока (это то, что я создаю). Тем не менее, мне удалось все это сделать, но теперь у меня возникли проблемы с методом DirectRead, поскольку я не знаю, как вызвать делегат, как только он у меня в стеке. Видимо, мне нужно следующее излучение:

ilGenerator.Emit(OpCodes.Callvirt, invokeMInfo);

где invokeMInfo - это метод Invoke в DirectReadAccessor, который я должен получить следующим образом:

MethodInfo invokeMInfo = typeof(DirectReadAccessor<MyClass>).GetMethod(
        "Invoke",                        // Name of the method.
        BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, // Binding attributes.
        null,                            // Binder.
        new Type[] { typeof(MyClass) },  // Types of the arguments.
        null                             // Modifiers for the arguments.
);

Опять же, проблема в том, что ни MyClass, ни DirectReadAccessor еще не существует. У меня есть TypeBuilder для MyClass и незаконченный тип DirectReadAccessor, который я создал следующим образом:

directReadAccessorType = typeof(DirectReadAccessor<>).MakeGenericType(typeBuilder);

Но если я пытаюсь вызвать GetMethod ("Invoke", ....) для directReadAccessorType, как показано выше, я получаю NotSupportedException, потому что не могу получить метод Invoke для незавершенного типа. Я проверил это предположение, сделав тот же вызов после завершения типа с:

typeBuilder.CreateType();

И действительно, я не получаю исключения в этом случае. Тем не менее, мне нужно иметь возможность получить MethodInfo метода Invoke перед завершением типа, в то время как я излучаю код для InitializeClass.

Странная ситуация: у меня будет делегат, когда он мне понадобится, но я не могу произвести код для его вызова. Кто-нибудь может предложить какую-либо помощь?

Большое спасибо и простите за длинный пост.

Ответы [ 3 ]

4 голосов
/ 03 марта 2010

Это сложная проблема. Я думаю, что вы должны быть в состоянии использовать TypeBuilder.GetMethod, чтобы получить MethodInfo, который вам нужен, используя вызов по линии

TypeBuilder.GetMethod(directReadAccessorType, 
    typeof(DirectReadAccessor<>).GetMethod("Invoke"));
0 голосов
/ 03 марта 2010

Имеет ли смысл минимизировать количество кода в сгенерированном классе?

Под этим я подразумеваю, что сгенерированный класс может реализовать интерфейс, который дает доступ к его данным. Через него вы можете реализовать дополнительные функции, которые могут быть закодированы в C # вместо IL.

0 голосов
/ 03 марта 2010

Вы пытались скомпилировать общий код и посмотреть на него, используя ILDASM? Он должен показать вам правильный IL и, мы надеемся, правильный генератор для генерации.

...