[英]Get generic type using Mono embedded
How to I create a generic List<String> object using mono embedded calls? 如何使用单声道嵌入式调用创建通用List <String>对象? I can get List's MonoClass: 我可以获得List的MonoClass:
MonoClass* list = mono_class_from_name(mscorlibimage,
"System.Collections.Generic", "List`1");
and I see in docs that there's 我在文档中看到有
mono_class_from_generic_parameter(MonoGenericParam*...)
but I have no idea where and how to get the MonoGenericParam. 但我不知道在哪里以及如何获得MonoGenericParam。 Or perhaps I need to construct a valid name for mono_class_from_name? 或许我需要为mono_class_from_name构建一个有效的名称? I think this can be a bit slower but I'd accept that for now. 我觉得这可能有点慢,但我现在接受了。 I tried 我试过了
MonoClass* list = mono_class_from_name(mscorlib::get().image, "System.Collections.Generic", "List`1[System.String]");
but no luck. 但没有运气。
UPDATE: 更新:
OK I found a way. 好的我找到了办法。 Still I'd like to see if there's an official way of doing thing, as this hack looks too dirty to me. 我仍然想知道是否有正式的做事方式,因为这个黑客对我来说太脏了。
Basically I searched mono sources for generic methods and found mono_class_bind_generic_parameters (see https://raw.github.com/mono/mono/master/mono/metadata/reflection.c ). 基本上我搜索了通用方法的单一来源,并找到了mono_class_bind_generic_parameters(参见https://raw.github.com/mono/mono/master/mono/metadata/reflection.c )。 I had to link to libmono-2.0.a in addition to .so to use it. 除了.so之外,我还必须链接到libmono-2.0.a才能使用它。 But it worked: 但它有效:
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);
I suppose I can take sources (UPDATE: hardly so) of these methods and reimplement them (they parse metadata, etc) - if I don't want to link to .a - but I wonder if there's a simpler way. 我想我可以获取这些方法的来源(更新:几乎没有)并重新实现它们(它们解析元数据等) - 如果我不想链接到.a - 但我想知道是否有更简单的方法。 Mono docs just don't answer anything, as they use to. 单声道文档只是不回答任何问题,因为他们习惯了。
UPDATE: found this thread: http://mono.1490590.n4.nabble.com/Embedded-API-Method-signature-not-found-with-generic-parameter-td4660157.html which seems to say that no embedded API exists for what I want (ie they do not bother to expose mono_class_bind_generic_parameters). 更新:发现这个帖子: http : //mono.1490590.n4.nabble.com/Embedded-API-Method-signature-not-found-with-generic-parameter-td4660157.html这似乎说没有嵌入式API存在为了我想要的(即他们不打扰公开mono_class_bind_generic_parameters)。 Can someone prove that it's correct? 有人可以证明这是正确的吗? With that method, by the way, I get MonoReflectionType* and no way to get back MonoType* from it - while it is as easy to as getting ->type from the structure - which is internal and access via functions to it is internal. 顺便说一下,使用那种方法,我得到MonoReflectionType *并且无法从中获取MonoType * - 虽然它很容易获取 - >从结构中输入 - 这是内部的,并且通过函数访问它是内部的。 Mono Embedded should be called "Mono Internal" instead. Mono Embedded应该被称为“Mono Internal”。
UPDATE: another method is to hack mono_class_inflate_generic_type using copy of internal structures: 更新:另一种方法是使用内部结构的副本来破解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);
This doesn't require static link to .a but is even a worse hack. 这不需要静态链接到.a,但甚至是更糟糕的黑客。 And mono_class_inflate_generic_type is marked as DEPRECATED - so, if this is deprecated, then which is the modern one? 并且mono_class_inflate_generic_type被标记为DEPRECATED - 因此,如果不推荐使用,那么哪个是现代的?
In many cases a mono embedding conundrum can be resolved by using a managed helper method. 在许多情况下,可以使用托管辅助方法解决单嵌入难题。 This is the approach used here. 这是这里使用的方法。
So we have: 所以我们有:
A managed helper method that accepts a generic type definition and an array of generic parameter types. 一种托管辅助方法,它接受泛型类型定义和泛型参数类型数组。
A client method that accepts a generic type definition name (eg: System.Collections.Generic.List`1), an assembly image that contains the type (or use an Assembly Qualified name) and an object of the required generic parameter type. 接受泛型类型定义名称的客户端方法(例如:System.Collections.Generic.List`1),包含类型的汇编映像(或使用程序集限定名称)和所需泛型参数类型的对象。 We retrieve the underlying monoType for the object. 我们检索对象的底层monoType。
Note that when passing type info into the managed layer it has to be an instance of MonoReflectionType as obtained from mono_type_get_object(). 请注意,将类型信息传递到托管图层时,它必须是从mono_type_get_object()获取的MonoReflectionType实例。
The managed helper method is trivial and does the actual instantiation: 托管帮助器方法很简单,并且实际实例化:
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;
}
The helper code is called, in this case, from Objective-C: 在这种情况下,从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;
}
For the complete code see Dubrovnik on Github 有关完整代码,请参阅Github上的Dubrovnik
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.