2013-07-13 20 views
6

Jak utworzyć ogólny obiekt List <String> za pomocą połączeń wbudowanych mono? Mogę liście za MonoClass:Uzyskaj typ ogólny za pomocą wbudowanego formatu Mono

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

i widzę w docs że istnieje

mono_class_from_generic_parameter(MonoGenericParam*...) 

ale nie mam pojęcia, gdzie i jak uzyskać MonoGenericParam. A może muszę utworzyć poprawną nazwę dla mono_class_from_name? Myślę, że to może być trochę wolniej, ale na razie to zaakceptuję. Spróbowałem:

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

ale bez powodzenia.

AKTUALIZACJA:

OK Znalazłem sposób. Nadal chciałbym sprawdzić, czy jest jakiś sposób na zrobienie czegoś, ponieważ ten hack wygląda na zbyt brudny dla mnie.

Zasadniczo szukałem źródeł mono dla ogólnych metod i znalazłem mono_class_bind_generic_parameters (patrz https://raw.github.com/mono/mono/master/mono/metadata/reflection.c). Musiałem połączyć się z libmono-2.0.a oprócz .so, aby go użyć. Ale to działało:

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

Przypuszczam mogę wziąć źródeł (aktualizacja: prawie tak) z tych metod i reimplement je (ich analizowania metadanych, etc) - jeśli nie chce połączyć się .a - ale Zastanawiam się, czy istnieje prostszy sposób. Mono-docs po prostu nie odpowiadają na nic, tak jak to robią.

AKTUALIZACJA: Znaleziono ten wątek: http://mono.1490590.n4.nabble.com/Embedded-API-Method-signature-not-found-with-generic-parameter-td4660157.html, który wydaje się mówić, że nie ma wbudowanego interfejsu API dla tego, co chcę (tj. Nie ma problemu z odsłonięciem mono_class_bind_generic_parameters). Czy ktoś może udowodnić, że to prawda? Dzięki tej metodzie otrzymuję MonoReflectionType * i nie mogę odzyskać MonoType * z niego - podczas gdy jest to tak proste jak pobieranie -> typ ze struktury - która jest wewnętrzna i dostęp poprzez funkcje do niej jest wewnętrzny. Mono Embedded powinno się nazywać "Mono Internal".

UPDATE: Inna metoda polega na użyciu włamać mono_class_inflate_generic_type kopię struktur wewnętrznych:

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

nie wymaga statycznego linku do .a ale jest nawet gorzej Hack. Typ mono_class_inflate_generic jest oznaczony jako ODRADZANA - tak więc, jeśli jest to przestarzałe, to najnowszym jest , które?

+0

Może wywoływanie metody statycznej Type.GetTypeFormTypeHandle, aby włączyć MonoType do MonoReflectionType i wywołać metodę instancji MakeGenericType na tym i uzyskać wartość fr om resoults Właściwość TypeHandle, która powinna być wskaźnikiem dla MonoType. Są to tylko domysły, których nigdy nie używałem Mono Embedded. – user629926

+0

Tak, na tym forum znalazłem sposób, który wymaga użycia TypeHandle IntPtr i rozpakowania go. Jest to najbezpieczniejszy sposób bez hackowania, ale używanie pomocników C# do utworzenia typu osadzonego wygląda dla mnie trochę niezręcznie. – queen3

+0

To jest świetne pytanie, które należy zadać na liście dyskusyjnej mono-devel (http://lists.ximian.com/mailman/listinfo/mono-devel-list) –

Odpowiedz

1

W wielu przypadkach zagadka wbudowanego mono może zostać rozwiązana przy użyciu zarządzanej metody pomocniczej. Jest to podejście stosowane tutaj.

Więc mamy:

  1. Zarządzany metody pomocnika, który akceptuje definicji typu rodzajowego i tablicę generycznych typów parametrów.

  2. Metoda klienta, która akceptuje ogólną nazwę definicji typu (np. System.Collections.Generic.List`1), obraz zespołu, który zawiera typ (lub używa nazwy kwalifikowanej złożenia) i obiekt wymaganego ogólny typ parametru. Pobieramy podstawowy monoType dla obiektu.

Należy pamiętać, że podczas przechodzenia informacje wpisać w zarządzanym warstwy musi być instancją MonoReflectionType otrzymany od mono_type_get_object().

zarządzanego metoda pomocnik jest trywialne i robi rzeczywistego konkretyzacji:

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

Kod pomocnik nazywany jest w tym przypadku, z 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; 
} 

Dla kompletnego kodu zobaczyć Dubrovnik na Github

Powiązane problemy