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[]) methodMonoMethod* 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 callMonoClass* testClass = mono_class_from_name(monoImage,"MonoGenerics","TestClass");// find GenericMethod method from our TestClass, the method that we want to invokeMonoMethod* 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 instanceMonoClass* monoGenericMethodClass = mono_object_get_class(methodInfo);// MethodHandle property of MethodInfo classMonoProperty* methodHandleProperty = mono_class_get_property_from_name(monoGenericMethodClass, "MethodHandle");// the getter of the above propertyMonoMethod* getMethodHandleMethod = mono_property_get_get_method(methodHandleProperty);// invoke the getter from aboveMonoObject* 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.