How can I send a call to a delegate whose type is not completed at the time of emission?

I am having a problem calling a delegate whose type is not completed at the time of emitting. I will clarify: I declared the following delegate type:

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

And now I'm trying to dynamically (i.e. using TypeBuilder) create the following class:

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

}

* on open delegate instances .

, MyClass , directReadAccessors, DirectReadAccessor [], InitalizeClass, MyClass, (, ). , , DirectRead, , , . -, emit:

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

, . , Invoke MethodInfo , InitializeClass.

: , , . - ?

, .

+3
3

. , TypeBuilder.GetMethod MethodInfo,

TypeBuilder.GetMethod(directReadAccessorType, 
    typeof(DirectReadAccessor<>).GetMethod("Invoke"));
+4

ILDASM? IL , , .

0

Does it make sense to minimize the amount of code in the generated class?

By this, I mean that the generated class could implement an interface that gives access to its data. Thanks to this, you can implement additional functions that can be encoded in C # instead of IL.

0
source

Source: https://habr.com/ru/post/1735190/


All Articles