Mono嵌入,从C中调用C#泛型方法

5

我在使用C语言时遇到了调用泛型方法(静态和非静态)的困难。

最大的问题是调用泛型方法基本上没有文档说明,在mono仓库中也没有示例,但是文档中提到这是可能的:

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);

不幸的是,这并没有什么帮助,因为它没有展示一个完整的例子,无论我做什么(使用 mono_object_get_class 或者不使用)调用通用方法时都会出现警告,接着崩溃。

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

以下是一个示例的C#类和调用它的C代码。调用非泛型方法没问题,但我不知道如何调用泛型方法。我会感激任何可以帮助我的技巧。

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);
      } 
  }
}

示例 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个回答

3
您不能以这种方式调用通用方法,不幸的是文档有点误导。如果您想使用字符串参数调用public void GenericMember<T>(T t),则必须找到签名为public void GenericMember<String>(String t)的方法,并在其上使用mono_runtime_invoke
更简单的方法是通过C#实用程序方法使用MethodInfo.MakeGenericMethod方法:
public static IntPtr Utility(MethodInfo method, Type type)
{
  return method.MakeGenericMethod(type).MethodHandle.Value;
}

使用嵌入式Mono API查找Utility方法,用代表GenericMethod<T>(T t)方法的MonoMethod*和您想要的类型(在您的示例中为String)调用它。此调用的返回值将是一个MonoMethod*,表示GenericMethod<String>(String t)。这就是您需要调用的方法。
我在这里发布了一篇详细的带有源代码的文章。

这对我不起作用,因为我嵌入的C#库太大了,无法添加所有实用方法。请提供您在链接http://www.giorgosdimtsas.net/embedded-mono-generic-method/中遇到的样板代码的详细信息。 - Howard Rubin
1
@HowardRubin 这里是一个示例,它不使用实用程序方法,在 Mono 4.0.1 上进行了测试。 毕竟,这不是很多代码。 - Giorgos Dimtsas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接