Instancier une classe générique avec un type dynamique et appeler une méthode appartenant à cette classe.#

J’ai rencontré ce problème en développant une couche d’accès aux données générique avec le compact framework. Voici le problème : J’ai développé une classe générique CRUD<T> qui permet de faire du CRUD simple. Pour ça j’ai utilisé les attributs pour décorer mes propriétés d’entités et dire que telle classe correspond à telle table et que telle propriété correspond à tel champ dans cette table. Ensuite et à l’aide de System.Reflection on regarde les attributs de la classe et des propriétés, on génère le sql correspondant à l’entité passée en paramètre et on exécute de la base.

Bon tout ça marche bien, maintenant supposons que l’on ait la classe suivante :

    public class Personne
    {

        int id;

        List&lt;Voiture&gt; Voitures;

    }

Il faudrait donner la possibilité d’auto charger les voitures d’une personne au même moment qu’on charge une personne. Donc on rajoute un attribut sur la propriété de type List<Voiture>dans la classe Personne pour dire que c’est une entité liée et en parcourant les attributs de ma classe pour générer le sql, quand je rencontre ce type d’attribut, je voudrais rappeler ma classe CRUD<T> avec T = Voiture pour obtenir la liste de voitures correspondantes à la personne. Or on ne sait pas par avance que c’est des Voitures ce n’est qu’au Runtime que je saurais que c’est des voitures donc le problème est le suivant : invoquer ma classe CRUD<T> avec un T dynamique.

Pour ce faire il y a 2 solutions ou plutôt 2 types de solutions :

- Contourner le problème en disant par exemple que de toutes les façons que c’est nul de vouloir auto charger les liens et de laisser ça à la demande du développeur.

- Utiliser ce qui existe dans le compact framework pour réussir

Je me suis plutôt focalisé sur le 2ème type de solution même si je ne suis pas en désaccord total avec le 1er type.

On dispose donc d’une variable « typeVoiture » de type « Type » qui contient le type « Voiture »

Pour créer le type CRUD<Voiture> on a à notre disposition dans Type la méthode MakeGenericType, on peut donc procéder de la manière suivante :

Type crud = typeof(CRUD&lt;&gt;);
Type[] typeArgs = { typeVoiture }; 
Type repositoryType = crud.MakeGenericType(typeArgs);

Et pour en créer une instance il suffit d’utiliser Activator.CreateInstance de la manière suivante :

object repository = Activator.CreateInstance(repositoryType);

On remarque que notre instance est de type « object », on ne peut donc pas utiliser directement ses méthodes et on ne peut pas le caster non plus puisqu’on ne peut pas écrire CRUD<typeVoiture.GetType()>.

Le seul moyen (que je connaisse en tout cas) est le suivant : On construit un objet de type « MethodInfo » à partir de l’instance de type générique qu’on a créé précédemment. Ensuite, on construit un tableau d’object qui correspond aux paramètres de la méthode à appeler et enfin on l’appelle en utilisant la méthode Invoke.

MethodInfo genericMethod = repositoryType.GetMethod("GetByForeignKey"); paramList = new object[2]; paramList[0] = param1; paramList[1] = param2;

genericMethod.Invoke(repository, paramList);

SI vous connaissez un autre moyen de faire, ou si vous voulez juste réagir, nhésitez pas, commentez ce post ;)

Thursday, October 01, 2009 9:43:25 PM (Romance Standard Time, UTC+01:00) #    Comments [0]  | 

 

All content © 2012, Zied Nemili