使用Mono嵌入式获取泛型类型

时间:2013-07-13 08:29:49

标签: mono mono-embedding

如何创建通用列表< String>对象使用单声道嵌入调用?我可以获得List的MonoClass:

MonoClass* list = mono_class_from_name(mscorlibimage,
     "System.Collections.Generic", "List`1");

我在文档中看到有

mono_class_from_generic_parameter(MonoGenericParam*...)

但我不知道在哪里以及如何获得MonoGenericParam。或许我需要为mono_class_from_name构建一个有效的名称?我觉得这可能有点慢,但我现在接受了。我试过了

MonoClass* list = mono_class_from_name(mscorlib::get().image, "System.Collections.Generic", "List`1[System.String]");

但没有运气。

更新:

好的,我找到了办法。我仍然想知道是否有官方做事的方式,因为这个黑客对我来说太脏了。

基本上我搜索了通用方法的单一来源,并找到了mono_class_bind_generic_parameters(参见https://raw.github.com/mono/mono/master/mono/metadata/reflection.c)。除了.so之外,我还必须链接到libmono-2.0.a才能使用它。但它奏效了:

extern "C" MonoClass*
mono_class_bind_generic_parameters(MonoClass *klass, 
    int type_argc, MonoType **types, bool is_dynamic);

MonoClass* list = mono_class_from_name(mscorlib::get().image,
    "System.Collections.Generic", "List`1");
MonoClass* strcls = mono_class_from_name(mscorlib::get().image, "System", "String");
printf("str class: %p\n", strcls);
MonoType* strtype = mono_class_get_type(strcls);
printf("str type: %p\n", strtype);
MonoType* types[1];
types[0] = strtype;
list = mono_class_bind_generic_parameters(list, 1, types, false);
printf("list[string] class: %p\n", list);
MonoObject* obj = mono_object_new(domain, list);
printf("list[string] created: %p\n", obj);

我想我可以获取这些方法的来源(更新:几乎没有)并重新实现它们(它们解析元数据等) - 如果我不想链接到.a - 但我想知道是否有更简单的方法。单声道文档只是不回答任何问题,因为他们习惯了。

更新:发现这个帖子:http://mono.1490590.n4.nabble.com/Embedded-API-Method-signature-not-found-with-generic-parameter-td4660157.html似乎没有嵌入式API存在于我想要的东西(即他们不打算公开mono_class_bind_generic_parameters)。有人可以证明这是正确的吗?顺便说一句,顺便说一下,我得到MonoReflectionType *并且无法从中获取MonoType * - 虽然它很容易获得 - >从结构中输入 - 这是内部的,并且通过函数访问它是内部的。 Mono Embedded应该被称为“Mono Internal”。

更新:另一种方法是使用内部结构的副本来破解mono_class_inflate_generic_type:

struct _MonoGenericInst {
        uint32_t id;                       /* unique ID for debugging */
        uint32_t type_argc    : 22;        /* number of type arguments */
        uint32_t is_open      :  1;        /* if this is an open type */
        MonoType *type_argv [1];
};

struct _MonoGenericContext {
        /* The instantiation corresponding to the class generic parameters */
        MonoGenericInst *class_inst;
        /* The instantiation corresponding to the method generic parameters */
        void *method_inst;
};

   _MonoGenericInst clsctx;
   clsctx.type_argc = 1;
   clsctx.is_open = 0;
   clsctx.type_argv[0] = mono_class_get_type(System::String::_SClass());
   MonoGenericContext ctx;
   ctx.method_inst = 0;
   ctx.class_inst = &clsctx;
   MonoType* lt = mono_class_inflate_generic_type(
      mono_class_get_type(System::Collections::Generic::List<System::String>::_SClass()),
      &ctx);

这不需要静态链接到.a,但甚至是更糟糕的黑客。并且mono_class_inflate_generic_type被标记为DEPRECATED - 所以,如果不推荐这样做,那么哪个是现代的?

1 个答案:

答案 0 :(得分:1)

在许多情况下,可以使用托管辅助方法解决单嵌入难题。这是这里使用的方法。

所以我们有:

  1. 托管辅助方法,它接受泛型类型定义和泛型参数类型数组。

  2. 接受泛型类型定义名称的客户端方法(例如:System.Collections.Generic.List`1),包含类型(或使用程序集限定名称)的程序集图像和必需的通用参数类型。我们检索对象的底层monoType。

  3. 请注意,将类型信息传递到托管图层时,它必须是从mono_type_get_object()获取的MonoReflectionType实例。

    托管辅助方法很简单,并且实际实例化:

        public static object CreateInstanceOfGenericType(Type genericTypeDefinition, Type[] parms)
        {
            // construct type from definition
            Type constructedType = genericTypeDefinition.MakeGenericType(parms);
    
            // create instance of constructed type
            object obj = Activator.CreateInstance(constructedType);
    
            return obj;
        }
    

    在这种情况下,从Objective-C:

    调用帮助程序代码
    + (id)createInstanceOfGenericTypeDefinition:(char *)genericTypeDefinitionName monoImage:(MonoImage *)monoImage itemObject:(id)itemObject
    {
        // get the contained item monoType
        MonoType *monoType = [DBType monoTypeForMonoObject:[itemObject monoObject]];
        MonoReflectionType *monoReflectionType = mono_type_get_object([DBManagedEnvironment currentDomain], monoType);
    
        // build a System.Array of item types
        DBManagedObject *argType = [[DBManagedObject alloc] initWithMonoObject:(MonoObject *)monoReflectionType];
        NSArray *argTypes = @[argType];
        DBSystem_Array *dbsAargTypes = [argTypes dbsArrayWithTypeName:@"System.Type"];
    
        // get the generic type definition
        //
        // Retrieves a MonoType from given name. If the name is not fully qualified,
        // it defaults to get the type from the image or, if image is NULL or loading
        // from it fails, uses corlib.
        // This is the embedded equivalent of System.Type.GetType();
        MonoType *monoGenericTypeDefinition = mono_reflection_type_from_name(genericTypeDefinitionName, monoImage);
    
        // create instance using helper method
        MonoMethod *helperMethod = [DBManagedEnvironment dubrovnikMonoMethodWithName:"CreateInstanceOfGenericType" className:"Dubrovnik.FrameworkHelper.GenericHelper" argCount:2];
        void *hargs [2];
        hargs[0] = mono_type_get_object([DBManagedEnvironment currentDomain], monoGenericTypeDefinition);
        hargs[1] = [dbsAargTypes monoArray]; // a monoArray *
    
        MonoObject *monoException = NULL;
        MonoObject *monoObject = mono_runtime_invoke(helperMethod, NULL, hargs, &monoException);
        if (monoException) NSRaiseExceptionFromMonoException(monoException);
    
        id object = [System_Object subclassObjectWithMonoObject:monoObject];
    
        return object;
    }
    

    有关完整代码,请参阅Github上的Dubrovnik