0

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.

2
Contributors
3
Replies
4
Views
6 Years
Discussion Span
Last Post by blackblizzard
0

In case anyone is insterested, they answered this for me at stackoverflow. The following call works:

TypeBuilder.GetMethod(directReadAccessorType, typeof(DirectReadAccessor<>).GetMethod("Invoke"));
This question has already been answered. Start a new discussion instead.
Have something to contribute to this discussion? Please be thoughtful, detailed and courteous, and be sure to adhere to our posting rules.