2013-07-13 5 views
6

Wie erstelle ich eine generische Liste <String> Objekt mit Mono eingebettete Aufrufe? Ich kann List MonoClass erhalten:Get generic type mit Mono eingebettet

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

und ich in docs sehen, dass es

mono_class_from_generic_parameter(MonoGenericParam*...) 

, aber ich habe keine Ahnung, wo und wie die MonoGenericParam zu bekommen. Oder muss ich vielleicht einen gültigen Namen für mono_class_from_name erstellen? Ich denke, das kann ein bisschen langsamer sein, aber ich würde das jetzt akzeptieren. Ich versuchte

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

aber kein Glück.

UPDATE:

OK fand ich einen Weg. Trotzdem würde ich gerne sehen, ob es eine offizielle Art und Weise zu tun gibt, da dieser Hack mir zu schmutzig aussieht.

Grundsätzlich habe ich Monoquellen für generische Methoden gesucht und mono_class_bind_generic_parameters gefunden (siehe https://raw.github.com/mono/mono/master/mono/metadata/reflection.c). Ich musste zusätzlich zu .so eine Verbindung zu libmono-2.0.a herstellen, um es zu benutzen. Aber es funktionierte:

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

Ich glaube, ich Quellen nehmen kann (UPDATE: kaum so) dieser Methoden und neu implementieren sie (sie analysieren Metadaten, etc.) - wenn ich will nicht zu .a verbinden - aber Ich frage mich, ob es einen einfacheren Weg gibt. Mono-Dokumente antworten einfach nicht, wie sie es gewohnt sind.

UPDATE: fand diesen Thread: http://mono.1490590.n4.nabble.com/Embedded-API-Method-signature-not-found-with-generic-parameter-td4660157.html was scheint zu sagen, dass keine eingebettete API existiert für das, was ich will (d. H. Sie sind nicht bereit, mono_class_bind_generic_parameters zu exponieren). Kann jemand beweisen, dass es richtig ist? Mit dieser Methode bekomme ich übrigens MonoReflectionType * und keine Möglichkeit, MonoType * daraus zurückzuholen - obwohl es so einfach ist, -> aus der Struktur zu tippen - was intern ist und über Funktionen darauf zugreifen ist intern. Mono Embedded sollte stattdessen "Mono Internal" heißen.

UPDATE: eine andere Methode ist mono_class_inflate_generic_type mit Kopie der internen Strukturen zu hacken:

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

Dies ist nicht statisch Link zu .a erfordert, sondern ist auch ein schlechter Hack. Und mono_class_inflate_generic_type ist als DEPRECATED gekennzeichnet - also, wenn dies veraltet ist, dann welche ist die moderne?

+0

Vielleicht die statische Methode Type.GetTypeFormTypeHandle aufrufen, um MonoType in MonoReflectionType umzuwandeln und MakeGenericType-Instanzmethode darauf aufzurufen und Wert fr zu erhalten om resultt TypeHandle-Eigenschaft, die Zeiger auf MonoType sein soll. Dies sind nur Vermutungen, die ich eigentlich nie Mono Embedded verwendet habe. – user629926

+0

Ja, in diesem Forum habe ich dann einen Weg gefunden, der das Verwenden von TypeHandle IntPtr beinhaltet und das Unboxing. Dies ist der sicherste Weg ohne Hacks, aber C# Helfer zu verwenden, nur um eingebettete Typen zu erstellen, sieht für mich ein bisschen peinlich aus. – queen3

+0

Dies ist eine gute Frage, die auf der Mono-devel-Mailingliste gestellt werden muss (http://lists.ximian.com/mailman/listinfo/mono-devel-list). –

Antwort

1

In vielen Fällen kann ein Mono-Einbettungsproblem mithilfe einer verwalteten Hilfsmethode gelöst werden. Dies ist der hier verwendete Ansatz. So

haben wir:

  1. Ein Helfer-Methode verwaltet, die eine generische Typdefinition und eine Reihe von generischen Parametertypen akzeptiert.

  2. Eine Clientmethode, die einen generischen Typdefinitionsnamen akzeptiert (zB: System.Collections.Generic.List`1), ein Assembly-Image, das den Typ (oder einen Assembly Qualified-Namen) und ein Objekt des erforderlichen Typs enthält allgemeiner Parametertyp Wir rufen den zugrunde liegenden monoType für das Objekt ab.

anzumerken, dass, wenn Informationen in die Art verwaltet Schicht Hindurchleiten eine Instanz von MonoReflectionType sein muss, wie aus mono_type_get_object erhalten().

Die verwaltete Hilfsmethode ist trivial und führt die eigentliche Instantiierung:

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

Der Helfer-Code genannt wird, in diesem Fall von 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; 
} 

Für den vollständigen Code zu sehen Dubrovnik auf Github