【问题标题】:Passing C# enum from C++ using mono使用单声道从 C++ 传递 C# 枚举
【发布时间】:2023-03-31 01:09:02
【问题描述】:

为什么我不能为采用枚举的方法获取 MonoMethod*,
有没有办法列出mono知道的方法?

这是我正在尝试做的简化示例。我尝试了 (Windows) ildasm 报告的不同组合,但没有成功。

// enum.cs
namespace EnumTest
{
    class EnumClass
    {
        public enum HelloType { Hi, Hey, Howdy, Greetings, Aloha };

        public static void SetDefault() { type_ = HelloType.Hi; }

        public static void SetType(HelloType h) { type_ = h; }

        public static HelloType type_;
    }
}

// enum.cpp
#include <mono/jit/jit.h>
#include <mono/metadata/assembly.h>
#include <mono/metadata/debug-helpers.h>

int main(int argc, char* argv[]) {
  MonoDomain* domain = mono_jit_init("enum.dll");
  MonoAssembly* assembly = mono_domain_assembly_open(domain, "enum.dll");
  MonoImage* image = mono_assembly_get_image(assembly);
  MonoClass* enumClass = mono_class_from_name(image, "EnumTest", "EnumClass");

  MonoMethodDesc* defaultDesc = mono_method_desc_new("EnumTest.EnumClass:SetDefault()", false);
  MonoMethod* defaultMethod = mono_method_desc_search_in_class(defaultDesc, enumClass);

  printf("defaultDesc from mono_method_desc_new() is %p\n", defaultDesc);
  printf("defaultMethod from mono_method_desc_search_in_class() is %p\n\n", defaultMethod);


  MonoMethodDesc* typeDesc = mono_method_desc_new("EnumTest.EnumClass:SetType(HelloType)", false);
  MonoMethod* typeMethod = mono_method_desc_search_in_class(typeDesc, enumClass);

  printf("typeDesc from mono_method_desc_new() is %p\n", typeDesc);
  printf("typeMethod from mono_method_desc_search_in_class() is %p      <------\n", typeMethod);


  mono_jit_cleanup(domain);
}

$ mcs /nologo /warn:4 /debug:pdbonly /o  /out:enum.dll /target:library enum.cs
$ gcc enum.cpp -g3 `pkg-config --cflags --libs mono-2` -o enum
$ ./enum
defaultDesc from mono_method_desc_new() is 0x1443920
defaultMethod from mono_method_desc_search_in_class() is 0x13dce40

typeDesc from mono_method_desc_new() is 0x1444590
typeMethod from mono_method_desc_search_in_class() is (nil)      <------
$ uname -a
Linux U14-OOXML 3.16.0-37-generic #51~14.04.1-Ubuntu SMP Wed May 6 15:23:14 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux

【问题讨论】:

  • 尝试使用 mono_class_get_methods 迭代所有类方法 - 方法是否显示在那里?
  • 在使用 mono_class_get_methods() 进行迭代时,会出现有问题的方法 (SetType)。并且使用 mono_method_signature()、mono_signature_get_params() 和 mono_type_get_name() 表明内部 mono 知道它的参数类型是 EnumTest.EnumClass.HelloType 所以看起来我上面的代码是正确的。

标签: c# c++ .net enums mono


【解决方案1】:

看起来参数类型需要完整的类型名称。

我使用 mono_method_full_name 和第二个参数 signature true 来获取签名(我使用了我自己的测试类,结构相同但名称不同):

MonoDomain* domain = mono_jit_init(CSHARP_LIB);
MonoAssembly* assembly = mono_domain_assembly_open(domain, CSHARP_LIB);
MonoImage* image = mono_assembly_get_image(assembly);
MonoClass* sandboxClass = mono_class_from_name(image, "CSharp_ClassLibrary", "Sandbox");

void* ptr = 0;
MonoMethod* iter;

while ((iter = mono_class_get_methods(sandboxClass, &ptr)) != NULL)
{
    printf("--------------------------------\n");
    const char* name = mono_method_get_name(iter);
    MonoMethodDesc* methodDesc = mono_method_desc_from_method(iter);

    const char* paramNames = "";
    mono_method_get_param_names(iter, &paramNames);

    printf("Name: %s\n", name);
    printf("Full name: %s\n", mono_method_full_name(iter, true));
    printf("    namespace: %s\n", methodDesc ->namespace);
    printf("    class:     %s\n", methodDesc ->klass);
    printf("    name:      %s\n", methodDesc ->name);
    printf("    args:      %s\n", methodDesc ->args);
    printf("    num_args:  %d\n", methodDesc ->num_args);
    printf("    paramnames:%s\n", paramNames);
}

我收到的输出是这样的:

--------------------------------
Name: SetDefault
Full name: CSharp_ClassLibrary.Sandbox:SetDefault ()
    namespace: CSharp_ClassLibrary
    class:     Sandbox
    name:      SetDefault
    args:      (null)
    num_args:  0
    paramnames:
--------------------------------
Name: SetType
Full name: CSharp_ClassLibrary.Sandbox:SetType (CSharp_ClassLibrary.Sandbox/HelloType)
    namespace: CSharp_ClassLibrary
    class:     Sandbox
    name:      SetType
    args:      (null)
    num_args:  0
    paramnames:h
--------------------------------
Name: .ctor
Full name: CSharp_ClassLibrary.Sandbox:.ctor ()
    namespace: CSharp_ClassLibrary
    class:     Sandbox
    name:      .ctor
    args:      (null)
    num_args:  0
    paramnames:

所以要修复你的代码,你只需在参数类型之前添加类名:

MonoMethodDesc* typeDesc = mono_method_desc_new("EnumTest.EnumClass:SetType(EnumClass/HelloType)", false);
MonoMethod* typeMethod = mono_method_desc_search_in_class(typeDesc, enumClass);

至少对我来说,这很好用!

【讨论】:

  • 您的示例代码并不完全正确,mono_method_get_param_names。您的代码将导致堆栈崩溃。尝试:const char* paramNames[128] = { 0 }; mono_method_get_param_names(iter, paramNames);
  • 访问 methodDesc 成员会导致编译器错误 - 成员访问不完整类型。
  • @awattar 这个答案写于 2015 年。从那时起,Mono API 可能发生了重大变化。
  • 我假设但也搜索了 github.com/mono/mono/blob/main/mono/metadata/debug-helpers.h 的历史并没有发现 MonoMethodDesc 结构被完全定义为 public。
  • 我明白了。 mono/metadata/class.h 中可能有相应的函数用于获取字段。随时提出修改建议或留下新的最新答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-01
  • 2015-04-26
相关资源
最近更新 更多