Get generic type with built-in mono

How to create a shared list of <String> object using mono-inline calls? I can get a list of MonoClass:

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

and I see in the documents that there

 mono_class_from_generic_parameter(MonoGenericParam*...) 

but I have no idea where and how to get MonoGenericParam. Or maybe I need to create a valid name for mono_class_from_name? I think this might be a little slower, but I would agree to that. 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. However, I would like to see if there is an official way to do something, as this hack looks too dirty for me.

Basically I searched for mono sources for common methods and found mono_class_bind_generic_parameters (see https://raw.github.com/mono/mono/master/mono/metadata/reflection.c ). I had to reference libmono-2.0.a in addition to .so to use it. 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 believe that I can use the sources (UPDATE: unlikely) of these methods and redefine them (they analyze metadata, etc.) - if I do not want to refer to .a - but I wonder if there is an easier way. Mono documents simply do not respond as they use.

UPDATE: found this chain: http://mono.1490590.n4.nabble.com/Embedded-API-Method-signature-not-found-with-generic-parameter-td4660157.html , which does not seem to contain any built-in API for what I want (i.e. they don’t bother to set mono_class_bind_generic_parameters). Can anyone prove that this is correct? With this method, by the way, I get MonoReflectionType * and do not get MonoType * from it, while it is as easy as get-> type from a structure that is internal and access through functions to it is internal. Instead, Mono Embedded should be called "Mono Internal."

UPDATE: another way to crack a mono_class_inflate_generic_type file using a copy of internal structures:

 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 does not require a static reference to .a, but it is even worse. And mono_class_inflate_generic_type is labeled DEPRECATED - so if it is deprecated, then which one is modern?

+6
source share
1 answer

In many cases, a monolithic puzzle can be solved using the guided assistant 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 takes the name of a generic type definition (for example: System.Collections.Generic.List`1), an assembly image that contains the type (or uses the name assigned to the assembly), and the object the required generic parameter type is. We retrieve the base monoType for the object.

Note that when passing type information to a managed layer, it must be an instance of MonoReflectionType derived from mono_type_get_object ().

The managed helper method is trivial and does the actual creation:

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

In this case, the helper code is called from 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 full code see Dubrovnik on Github

+1
source

Source: https://habr.com/ru/post/949356/


All Articles