Hi everyone. I'm having trouble emitting a call to a delegate whose type is unfinished at the time of the emit. I'll elaborate: I'm trying to dynamically (i.e., with a TypeBuilder
) create the following class:
public MyClass {
// Delegate type. The 'firstArgument' will be 'this', i.e., this is an open instance method:
// the implicit argument is here given explicitly, in 'firstArgument'.
// (below there's a link explaining open instance methods; I couldn't get it to work within
// the code block)
public delegate Object DirectReadAccessor<T>(T firstArgument);
// 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.
);
}
}
}
* About open instance methods (and other things).
This has been tricky because MyClass
doesn't exist when I'm trying to declare the field directReadAccessors
, which is of type DirectReadAccessor<MyClass>[]
, or when I emit the method InitalizeClass
, which again uses MyClass
, that doesn't exist yet (that's what I'm creating). However, I've managed to do all this, but now I'm having trouble with method DirectRead
, since I don't know how to call the delegate once I have it on the stack. Apparently what I need is the following emit:
ilGenerator.Emit(OpCodes.Callvirt, invokeMInfo);
where invokeMInfo
is the method Invoke
on DirectReadAccessor<MyClass>
, and which I should obtain like so:
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.
);
Again, the problem is that neither MyClass
nor DirectReadAccessor<MyClass>
exist yet. I have the TypeBuilder
for MyClass
and the unfinished DirectReadAccessor
type, which I've created like this:
directReadAccessorType = typeof(DirectReadAccessor<>).MakeGenericType(typeBuilder);
But if I try to call GetMethod("Invoke", ....)
on directReadAccessorType
as shown above I get a NotSupportedException
, because I cannot obtain the method Invoke
for an unfinished type. I've tested this assumption by making the same call after finalizing the type with:
typeBuilder.CreateType();
And indeed I do not get the exception in that case. However, I need to be able to get the Invoke
method's MethodInfo
before finalizing the type, while I'm emitting the code for InitializeClass
.
It's a strange situation: I'll have the delegate when I need it, but I cannot produce the code to invoke it. Can anyone offer any help?
Thanks so much, and sorry for the lengthy post.