2013-07-13 2 views
6

Comment créer une liste générique < objet chaîne > en utilisant mono appels intégrés? Je peux obtenir MonoClass List:Get type générique en utilisant Mono intégré

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

et je vois dans docs qu'il ya

mono_class_from_generic_parameter(MonoGenericParam*...) 

mais je ne sais pas où et comment obtenir le MonoGenericParam. Ou peut-être que j'ai besoin de construire un nom valide pour mono_class_from_name? Je pense que cela peut être un peu plus lent mais je l'accepterais pour l'instant. J'ai essayé

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

mais pas de chance.

MISE À JOUR:

OK, je trouve un moyen. Cependant, je voudrais voir s'il y a un moyen officiel de faire chose, que ce hack me semble trop sale.

Fondamentalement, j'ai cherché des sources mono pour des méthodes génériques et trouvé mono_class_bind_generic_parameters (voir https://raw.github.com/mono/mono/master/mono/metadata/reflection.c). Je devais créer un lien vers libmono-2.0.a en plus .so l'utiliser. Mais cela a fonctionné:

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

Je suppose que je peux prendre des sources (Mise à jour: à peine si) de ces méthodes et les ré-écrire (ils analysent les métadonnées, etc.) - si je ne veux pas créer un lien vers .a - mais Je me demande s'il y a un moyen plus simple. Les docs mono ne répondent à rien, comme ils le font. MISE À JOUR: trouvé ce fil de discussion: http://mono.1490590.n4.nabble.com/Embedded-API-Method-signature-not-found-with-generic-parameter-td4660157.html qui semble indiquer qu'il n'existe aucune API intégrée pour ce que je veux (c'est-à-dire qu'ils ne se soucient pas d'exposer mono_class_bind_generic_parameters). Quelqu'un peut-il prouver que c'est correct? Avec cette méthode, en passant, je reçois MonoReflectionType * et aucun moyen de revenir MonoType * de lui - alors qu'il est aussi facile comme obtenir -> le type de la structure - qui est interne et l'accès via des fonctions à elle est interne. Mono Embedded devrait être appelé "Mono Internal" à la place.

MISE A JOUR: Une autre méthode consiste à pirater mono_class_inflate_generic_type copie en utilisant des structures internes:

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

Cela ne nécessite pas le lien statique .a mais est encore pire hack. Et mono_class_inflate_generic_type est marqué comme DECONSEILLE - donc, si cela est dépréciée, alors qui est le moderne?

+0

Peut-être appelez-vous la méthode statique Type.GetTypeFormTypeHandle pour transformer MonoType en MonoReflectionType et invoquer la méthode d'instance MakeGenericType dessus et obtenir la valeur en om resoults TypeHandle propriété qui doit pointer vers MonoType. Ce ne sont que des suppositions que je n'ai jamais utilisé acto Mono Embedded. – user629926

+0

Oui, dans ce forum, j'ai ensuite trouvé un moyen qui implique l'utilisation de TypeHandle IntPtr et le déballage. C'est le moyen le plus sûr sans hacks, mais l'utilisation des assistants C# juste pour créer un type intégré semble un peu gênant pour moi. – queen3

+0

Ceci est une excellente question à poser à la liste de diffusion mono-devel (http://lists.ximian.com/mailman/listinfo/mono-devel-list) –

Répondre

1

Dans de nombreux cas, un casse-tête mono intégration peut être résolu en utilisant une méthode d'assistance gérée. C'est l'approche utilisée ici.

Nous avons donc:

  1. Une gestion méthode d'assistance qui accepte une définition de type générique et un éventail de types de paramètres génériques.

  2. Méthode client qui accepte un nom de définition de type générique (par exemple: System.Collections.Generic.List`1), une image de montage qui contient le type (ou utiliser un nom qualifié Assemblée) et un objet de la nécessaire type de paramètre générique. Nous récupérons le monoType sous-jacent pour l'objet.

Notez que lors du passage d'informations de type dans la couche gérée, il doit être une instance de MonoReflectionType obtenue à partir mono_type_get_object().

La méthode d'assistance gérée est trivial et fait l'instanciation réelle:

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

Le code d'aide est appelé, dans ce cas, de 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; 
} 

Pour le code complet voir Dubrovnik sur Github

Questions connexes