Question

J'ai une classe de base:

public abstract class StuffBase
{
    public abstract void DoSomething();
}

Et deux classes dérivées

public class Stuff1 : StuffBase
{
    public void DoSomething()
    {
        Console.WriteLine("Stuff 1 did something cool!");
    }
    public Stuff1()
    {
        Console.WriteLine("New stuff 1 reporting for duty!");
    }
}

public class Stuff2 : StuffBase
{
    public void DoSomething()
    {
        Console.WriteLine("Stuff 2 did something cool!");
    }
    public Stuff1()
    {
        Console.WriteLine("New stuff 2 reporting for duty!");
    }
}

Bon, disons que j'ai une liste d'éléments:

var items = new List<StuffBase>();
items.Add(new Stuff1());
items.Add(new Stuff2());

et je veux qu’ils appellent tous leur méthode DoSomething (). Je pouvais m'attendre à simplement parcourir la liste et à appeler leur méthode DoSomething (), alors disons que j'ai une méthode appelée AllDoSomething () qui itère simplement sur la liste et fait le travail:

public static void AllDoSomething(List<StuffBase> items)
{
    items.ForEach(i => i.DoSomething());
}

Quelle est la différence pratique de la méthode suivante?

public static void AllDoSomething<T>(List<T> items) where T: StuffBase
{
    items.ForEach(i => i.DoSomething());
}

Les deux méthodes apparaissent en termes réels, bien qu’elles soient syntaxiquement différentes, pour faire la même chose.

S'agit-il simplement de différentes manières de faire la même chose? Je comprends les génériques et les contraintes de type, mais je ne vois pas pourquoi j'utiliserais un moyen plutôt qu'un autre dans cet exemple.

Était-ce utile?

La solution

En effet, C # ne prend pas en charge les Covariance .

  

Plus formellement, en C # v2.0 si T est un   sous-type de U, alors T [] est un sous-type de   U [], mais G n'est pas un sous-type de G   (où G est un type générique quelconque). Dans   terminologie de la théorie des types, nous décrivons   ce comportement en disant que le tableau C #   les types sont & # 8220; covariant & # 8221; et générique   les types sont & # 8220; invariants & # 8221;.

Référence: http: // blogs. msdn.com/rmbyers/archive/2005/02/16/375079.aspx

Si vous utilisez la méthode suivante:

public static void AllDoSomething(List<StuffBase> items)
{
    items.ForEach(i => i.DoSomething());
}

var items = new List<Stuff2>();
x.AllDoSomething(items); //Does not compile

Où, comme si vous utilisiez la contrainte de type générique, ce sera le cas.

Pour plus d'informations sur Covariance et Contravariance], consultez La série d'articles d'Eric Lippert .

Autres articles à lire:

Autres conseils

Supposons que vous ayez une liste:

List<Stuff1> l = // get from somewhere

Maintenant, essayez:

AllDoSomething(l);

Avec la version générique, cela sera autorisé. Avec le non-générique, ça ne va pas. C'est la différence essentielle. Une liste de Stuff1 n'est pas une liste de StuffBase. Mais dans le cas générique, vous n'avez pas besoin que ce soit exactement une liste de <=>, donc c'est plus flexible.

Vous pouvez contourner ce problème en copiant d’abord votre liste de <=> dans une liste de <=>, afin de la rendre compatible avec la version non générique. Mais supposons que vous ayez une méthode:

List<T> TransformList<T>(List<T> input) where T : StuffBase
{
    List<T> output = new List<T>();

    foreach (T item in input)
    {
        // examine item and decide whether to discard it,
        // make new items, whatever
    }

    return output;
}

Sans génériques, vous pouvez accepter une liste de <=>, mais vous devez alors renvoyer une liste de <=>. L'appelant devrait utiliser des conversions s'il savait que les éléments étaient réellement d'un type dérivé. Les génériques vous permettent donc de conserver le type d’un argument et de le canaliser vers la méthode par le biais de la méthode.

Dans l'exemple que vous avez fourni, il n'y a pas de différence, mais essayez ce qui suit:

List<Stuff1> items = new List<Stuff1>();
items.Add(new Stuff1());
AllDoSomething(items);
AllDoSomething<StuffBase>(items);

Le premier appel fonctionne bien, mais le second ne se compile pas à cause d'une covariance générique

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top