单声道嵌入,从 C 调用 C# 泛型方法

Posted

技术标签:

【中文标题】单声道嵌入,从 C 调用 C# 泛型方法【英文标题】:mono embedding, call a C# generic method from C 【发布时间】:2014-03-08 18:15:38 【问题描述】:

我无法弄清楚如何从 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】:

您不能以这种方式调用泛型方法,不幸的是,文档有点误导。如果你想使用String 参数调用public void GenericMember&lt;T&gt;(T t),你必须找到带有签名public void GenericMember&lt;String&gt;(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&lt;T&gt;(T t) 方法的 MonoMethod* 和您想要的类型(在您的示例中为字符串)调用它。此调用的返回将是一个MonoMethod*,它将代表GenericMethod&lt;String&gt;(String t)。这是您需要调用的方法。

我用源代码here做了详细贴。

【讨论】:

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

以上是关于单声道嵌入,从 C 调用 C# 泛型方法的主要内容,如果未能解决你的问题,请参考以下文章

如何使用嵌入在 C++ 中的单声道编译 C# 代码?

单声道嵌入,在不知道命名空间的情况下获取 MonoClass*

使用 C++ 和嵌入式单声道调用 C# DLL 时无法加载程序集系统

嵌入式单声道:将数组从 C# DLL 返回/复制到 C++

在不知道类型是啥的情况下调用返回泛型集合的泛型方法? C#

C#泛型类,泛型接口,泛型方法,泛型委托怎么用