Embedded Mono: Invoking a C# generic method (Part 2)
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:
1
2
3
4
5
6
7
8
9
10
11
12
|
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:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
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.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
// 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:
1
2
3
4
5
6
7
8
9
|
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:
1
2
|
MonoObject
*
exception
=
NULL
;
MonoObject
*
methodInfo
=
mono_runtime_invoke
(
makeGenericMethod
,
monoReflectionMethod
,
makeGenArgs
,
&exception
)
;
|
We now have a MethodInfo instance, that represents the voidGenericMethod(String t) method. What we need now, is the value of its MethodHandle property:
1
2
3
4
5
6
7
8
9
10
11
|
// 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:
1
2
3
4
5
6
|
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.