Search code examples
c#cilmono.cecil

Importing methods with generic type parameters


I am currently working on adding a new feature to an existing API. Let's say I have a PerformTediousOperation method with a generic type parameter:

void PerformTediousOperation<T>()

This method is inside a Operator class, and can be invoked like this:

operatorInstance.PerformTediousOperation<T>()

I want to create a new Operator instance and invoke this method, whenever the user marks a type with the Operable attribute.

Currently, this is where I am stuck:

MethodReference performTediousOperationMethodReference =
    new MethodReference(
        name: "PerformTediousOperation",
        returnType: moduleDefinition.TypeSystem.Void,
        declaringType: operatorTypeReference)
    {
        HasThis = true
    };

The emitted IL code (in C#) is simply PerformTediousOperation();.

How can I fix this so that the emitted code is instead PerformTediousOperation<T>(), where T will be determined at runtime?

Please let me know if any more information is desired.


Solution

  • Here is an example of how to generate a method that has a generic type parameter using MonoCecil:

    MethodReference performTediousOperationMethodReference =
        new MethodReference(
            name: "PerformTediousOperation",
            returnType: moduleDefinition.TypeSystem.Void,
            declaringType: operatorTypeReference)
        {
            HasThis = true
        };
    
    var genericParameter = new GenericParameter("T", performTediousOperationMethodReference);
    performTediousOperationMethodReference.GenericParameters.Add(genericParameter);
    
    GenericInstanceMethod performTediousOperationInstanceMethod = 
        new GenericInstanceMethod(performTediousOperationMethodReference) 
            {
                GenericArguments = { moduleDefinition.ImportReference(typeof(int)) }
            };
    

    This generates PerformTediousOperation<int>().

    You may pass any other TypeReference instance to the GenericArguments field, and the output will differ accordingly. E.g. if you pass in moduleDefinition.ImportReference(typeof(string)) instead, the output will be PerformTediousOperation<string>().