У меня проблемы с отправкой вызова делегату, тип которого не завершен на момент отправки. Я уточню: я объявил следующий тип делегата:
// 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.
Это странная ситуация: у меня будет делегат, когда он мне понадобится, но я не могу создать код для его вызова. Может ли кто-нибудь помочь?
Большое спасибо и извините за пространный пост.