V. A.
V. A.

Reputation: 27

Calling generic method with Mono Cecil

I'd like to inject IL code into methods, which calls a Generic method (With return type and arguments).

public static T MyGenericMethod<T>(T genericArg, string nonGenericArg)
{
    //Do something with genericArg
    return genericArg;
}

I can call non generic methods, but I have no idea how to call a generic method.

My question is, how could I inject this generic method call into a method?

Example for Non-Generic method injection:

1, Open the assembly and get the non generic method info

        DefaultAssemblyResolver resolver = new DefaultAssemblyResolver();
        resolver.AddSearchDirectory(assemblyResolverPath);
        AssemblyDefinition myLibrary = AssemblyDefinition.ReadAssembly(assemblyPath, new ReaderParameters() { AssemblyResolver = resolver });

        MethodInfo writeLineMethod = typeof(Debug).GetMethod("WriteLine", new Type[] { typeof(string) });
        MethodReference writeLine = myLibrary.MainModule.Import(writeLineMethod);

2, Inject the "WriteLine" method into the choosen method:

                ILProcessor ilProcessor = method.Body.GetILProcessor();

                Instruction callWriteLine = ilProcessor.Create(OpCodes.Call, writeLine);

                ilProcessor.InsertBefore(ins, "CALL");
                ilProcessor.InsertBefore(ins, callWriteLine);

This will result the following extra IL instructions in the choosen method:

IL_0001: ldstr        "CALL"
IL_0006: call         void [mscorlib]System.Console::WriteLine(string)

But in case of a Generic method, I should receive this IL:

IL_0001: ldc.i4.s     10 // 0x0a
IL_0003: ldstr        "CALL"
IL_0008: call         !!0/*int32*/ ReturnTestModule.ReturnTest::MyGenericMethod<int32>(!!0/*int32*/, string)

I have to handle the generic arguments and the return value type definitely, but I do not know, how should I do it.

Upvotes: 1

Views: 2070

Answers (1)

Akos Nagy
Akos Nagy

Reputation: 4350

I think you are basically on the right track. All you have to do is get a reference to the generic method, like you did it for the non-generic version. The difference is that for a generic method, this will give you the MethodInfo of the open generic method and you have to close it first, using the MakeGeneric() method and passing the types that you want the method to have as generic type arguments.

MethodInfo openGenericMethod = typeof(Program).GetMethod("MyGenericMethod");
/// this will create a reference to MyGenericMethod<int>()
MethodInfo closedGenericMethod = openGenericMethod.MakeGenericMethod(typeof(int));

And then proceed with getting the MethodReference, creating the ILProcessor and inserting the instruction.

Upvotes: 0

Related Questions