Embedded Mono: Invoking a C# generic method (Part 2)

July 9, 2015-2 min read

A while ago I wrote about how to invoke a C# generic method, by using a helper method in the assembly. In this post, we will see how to invoke generic methods using solely the Mono embedding API. A much preferred alternative, since you don't pollute your assemblies with helper methods that are used by C++ only.

As before, the TestClass that contains the generic method:

using System;
namespace MonoGenerics
{
public class TestClass
{
public void GenericMethod<T>(T t)
{
Console.WriteLine(t);
}
}
}

As is the previous post, we will still use reflection to get a specialized instance of GenericMethod, but this time we will do it solely through the embedding API.

The first step is to find the MethodInfo.MakeGenericMethod method:

MonoAssembly* mscorlibAssembly = mono_domain_assembly_open(monoDomain,
"mono/lib/mono/4.0/mscorlib.dll");
MonoImage* systemImage = mono_assembly_get_image(mscorlibAssembly);
MonoClass* methodInfoClass = mono_class_from_name(systemImage,
"System.Reflection",
"MonoMethod");
// find the MethodInfo.MakeGenericMethod(Type[]) method
MonoMethod* makeGenericMethod = mono_class_get_method_from_name(methodInfoClass,
"MakeGenericMethod",
1);

Then, we want to find the TestClass.GenericMethod and get an instance of a MonoReflectionMethod, that represents the GenericMethod. On that instance, we will later call the makeGenericMethod MonoMethod that we got from above.

// Our test class, that contains the GenericMethod method, which we want to call
MonoClass* testClass = mono_class_from_name(monoImage,
"MonoGenerics",
"TestClass");
// find GenericMethod method from our TestClass, the method that we want to invoke
MonoMethod* genericMethod = mono_class_get_method_from_name(testClass,
"GenericMethod",
1);
MonoReflectionMethod* monoReflectionMethod = mono_method_get_object(monoDomain,
genericMethod,
testClass);

The MethodInfo.MakeGenericMethod method accepts an array of Types as its only parameter. Lets create that array:

MonoType* monoType = mono_reflection_type_from_name("System.String", monoImage);
MonoReflectionType* monoReflectionType = mono_type_get_object(monoDomain,
monoType);
// create an array of Types, that will be the argument to MethodInfo.MakeGenericMethod(Type[])
MonoArray* array = mono_array_new(monoDomain, mono_class_from_mono_type(monoType), 1);
mono_array_set(array, MonoReflectionType*, 0, monoReflectionType);
void* makeGenArgs[1];
makeGenArgs[0] = array;

Now we have have everything we need to call the MakeGenericMethod; a method definition, an instance to call it against and the method parameters:

MonoObject* exception = NULL;
MonoObject* methodInfo = mono_runtime_invoke(makeGenericMethod, monoReflectionMethod, makeGenArgs, &exception);

We now have a MethodInfo instance, that represents the void GenericMethod(String t) method. What we need now, is the value of its MethodHandle property:

// get the class definition of the methodInfo instance
MonoClass* monoGenericMethodClass = mono_object_get_class(methodInfo);
// MethodHandle property of MethodInfo class
MonoProperty* methodHandleProperty = mono_class_get_property_from_name(monoGenericMethodClass, "MethodHandle");
// the getter of the above property
MonoMethod* getMethodHandleMethod = mono_property_get_get_method(methodHandleProperty);
// invoke the getter from above
MonoObject* methodHandle = mono_runtime_invoke(getMethodHandleMethod, methodInfo, NULL, &exception);

All that is left to do is to unbox the methodHandle into a MonoMethod and invoke the latter as usual:

MonoMethod* specializedMethod = *(MonoMethod**) mono_object_unbox(methodHandle);
void* args[1];
args[0] = mono_string_new(monoDomain, "Finally!");
MonoObject* testClassInstance = mono_object_new(monoDomain, testClass);
mono_runtime_invoke(specializedMethod, testClassInstance, args, &exception);

That’s all for this tutorial. Full source code can be found here.