DY

DelahayeYourself

modules / M2104 /

TP10: Paramètres de type générique

Où en sommes nous ..

Reprenons notre classe Laboratory, suite au TP de la semaine dernière vous avez dû la modifier afin de créer quatre méthodes qui permettent chacune de créer une instance d'une espèce de dinosaure.

Laboratory UML class diagram
Diagramme UML de classe pour notre laboratoire

Toutefois cela implique de la redondance de code et surtout de devoir créer une nouvelle méthode à chaque ajout d'une espèce de dinosaure dans notre code.

Il serait donc plus intéressant de créer une méthode générique où l'on passe le type d'objet à créer au moment de l'appel afin d'éviter la redondance de code et surtout de rendre celui-ci générique et tolérant à l'ajout de nouvelle espèce.

Il s'agit des types génériques.

Paramètres de type générique

Dans une définition de méthode, le paramètre de type représente un espace réservé pour un type spécifié par le client au moment de créer une instance du type générique.

Utilisation d'un type générique

On peut définir une méthode qui utiliser un typé générique de cette manière (T est ici un type générique):

public T DoSomething<T>(T obj)
{
    return obj;
}
Notre laboratoire

Ainsi notre laboratoire peut s'écrire sous cette forme:

Laboratory UML class diagram
Diagramme UML de classe pour notre laboratoire
public class Laboratory
{
    public static TDinosaur CreateDinosaur<TDinosaur>(string name, int age=0)
    {
        //Do something magic here
    }
}
Utilisation de la classe Activator

Malheureusement il n'est pas possible de coder ceci:

public class Laboratory
{
    public static TDinosaur CreateDinosaur<TDinosaur>(string name, int age=0)
    {
        return new TDinosaur(typeof(TDinosaur), name, age);
    }
}

Nous allons donc devoir utiliser la classe Activator qui contient des méthodes permettant de créer des types d'objets localement ou à distance, ou d'obtenir des références à des objets distants existants.

Ainsi notre code deviendra équivalent à cela:

public static TDinosaur CreateDinosaur<TDinosaur>(string name, int age=0)
{
    return (TDinosaur)Activator.CreateInstance(typeof(TDinosaur), name, age);
}
  1. Implémentez les T.Us de cette nouvelle méthode CreateDinosaur,
  2. Implémentez cette méthode,
  3. Utilisez cette nouvelle méthode au sein de votre Main.
Erreur de conception ?

Nous avons créer notre méthode générique pour créer des dinosaures mais que se passe t'il dans ce cas:

Laboratory.CreateDinosaur<Diplodocus>("Nessie", 11);
Laboratory.CreateDinosaur<String>("Louis", 12);

Le compilateur permet de compiler ce programme toutefois nous avons une erreur au moment de l'exécution. Nous pouvons résoudre ce problème directement au sein de notre code en ajoutant une clause where à notre type générique.

public static TDinosaur CreateDinosaur<TDinosaur>(string name, int age=0) where TDinosaur: Dinosaur
{
    return (TDinosaur)Activator.CreateInstance(typeof(TDinosaur), name, age);
}

Ainsi au moment de la compilation nous forçons le compilateur à vérifier le type générique passé à notre méthode.

  1. Pouvez vous compiler votre programme maintenant ?
  2. Corrigez le pour pouvoir le compiler.
A vous de jouer

En reprenant notre diagramme de classe, faite en sorte que la méthode Hug puissent être appelé avec n'importe quel type de dinosaure via un type générique.