5

I am having trouble figuring out how to call generic method (both static and non-static) from C.

The biggest culprit is that calling generic methods is essentially undocumented, there are no examples in the mono repository but there's a mention that this is supposedly possible in the docs:

If you want to invoke generic methods, you must call the method on the "inflated" class, which you can obtain from the mono_object_get_class() MonoClass *clazz; MonoMethod *method; clazz = mono_object_get_class (obj); /* * If there are more Add methods declared, you * may use mono_method_desc_search_in_class (clazz, ":Add(T)"), * you must substitute ":Add(T)" with the correct type, for example * for List<int>, you would use ":Add(int)". */ method = mono_class_get_method_from_name (clazz, "Add", 1); mono_runtime_invoke (method, obj, args, &exception); 

Unfortunately this is not that helpful since it doesn't show a complete example, and no matter what I do (using mono_object_get_class or not) I end up with a warning followed by a crash when calling generic methods.

* Assertion: should not be reached at marshal.c:4315 SIGABRT stracktrace... 

Below a sample C# class and C code calling into it. Invoking non-generic methods works just fine but I have no clue how to invoke generic methods. I'd appreciate any tips that could help.

Sample CSharp

namespace foo { class MainClass { public static void Main(string[] args) { Console.WriteLine("Main"); } public void GenericMember<T>(T t) { Console.WriteLine(t); } public static void GenericStatic<T>(T t) { Console.WriteLine(t); } public void NonGenericMember(string t) { Console.WriteLine(t); } public static void NonGenericStatic(string t) { Console.WriteLine(t); } } } 

Sample C

#include <mono/jit/jit.h> #include <mono/metadata/mono-config.h> #include <mono/metadata/metadata.h> #include <mono/metadata/appdomain.h> #include <mono/metadata/class.h> #include <mono/metadata/assembly.h> #include <mono/metadata/image.h> #include <mono/metadata/object.h> #include <mono/metadata/debug-helpers.h> int main(int argc, char **argv) { mono_config_parse(NULL); MonoDomain *domain = mono_jit_init_version("app", "v4.0.30319"); MonoAssembly *assembly = mono_domain_assembly_open(domain, "foo.exe"); MonoImage *image = mono_assembly_get_image(assembly); mono_jit_exec(domain, assembly, argc, argv); MonoClass *klass = mono_class_from_name(image, "foo", "MainClass"); MonoObject *instance = mono_object_new(domain, klass) MonoString *string = mono_string_new(domain, "hello"); void *params[] = { string }; //NonGenericStatic call (works) MonoMethod *method = mono_class_get_method_from_name(klass, "NonGenericStatic", 1); mono_runtime_invoke(method, NULL, params, NULL); //NonGenericMember call (works); method = mono_class_get_method_from(klass, "NonGenericMember", 1); mono_runtime_invoke(method, instance, params, NULL); //GenericStatic call (fails) method = mono_class_get_method_from_name(klass, "GenericStatic", 1); mono_runtime_invoke(method, NULL, params, NULL); //GenericMember call (fails) method = mono_class_get_method_from_name(klass, "GenericMember", 1); mono_runtime_invoke(method, instance, params, NULL); mono_jit_cleanup(domain, assembly); return 0; } 

1 Answer 1

3

You cannot invoke generic methods that way and unfortunately the documentation is a bit misleading. If you want to invoke public void GenericMember<T>(T t) with a String parameter you have to find the method with signature public void GenericMember<String>(String t) and use mono_runtime_invoke on it.

The easier way to do this is to use the MethodInfo.MakeGenericMethod method through a C# utility method:

public static IntPtr Utility(MethodInfo method, Type type) { return method.MakeGenericMethod(type).MethodHandle.Value; } 

Using the embedded Mono API find the Utility method, invoke it with the MonoMethod* representing the GenericMethod<T>(T t) method and the Type that you want (String in your example). The return of this invoke will be a MonoMethod* that will represent GenericMethod<String>(String t). This is the method that you need to invoke.

I made a detailed post with source code here.

Sign up to request clarification or add additional context in comments.

2 Comments

This won't work for me because the C# lib I'm embedding is way too big to add all the utility methods. Please give details of the boilerplate code youj hit at in your link giorgosdimtsas.net/embedded-mono-generic-method
@HowardRubin here is an example that doesn't use utility methods, tested on Mono 4.0.1. It's not that much code after all.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.