Bonjour,

J'ai eu un soucis récemment avec le polymorphisme dans une liste.

Je vais poser le problème avant, ça sera peut être plus clair :

J'ai une classe abstraite A, et deux classes (B et C) qui en héritent :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
public abstract class A { public string Value { get; set; } }
public class B : A { public B(string value) { Value = value; } }
public class C : A { public C(string value) { Value = value; } }
Je veux faire un traitement quelconque sur une liste de ces objets (B et C).
Pour l'exemple disons que ce traitement c'est le remplacement d'un élément dans une liste par un autre.

Voilà le code :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Program
{
    static void Main(string[] args)
    {
        List<B> listB = new List<B> { new B("B1"), new B("B2"), new B("B3") };
        List<C> listC = new List<C> { new C("C1"), new C("C2"), new C("C3") };
 
        B b = new B("B22");
        C c = new C("C22");
 
        replace(listB[1], b, listB); // les valeurs de la liste deviennent "B1", "B22", "B3"
        replace(listC[1], c, listC); // les valeurs de la liste deviennent "C1", "C22", "C3"
    }
    // [...]
}
Afin de factoriser le code, je ne veux créer qu'une seule méthode replace qui fasse ce traitement pour les deux classes.

Pour coder cette fameuse méthode, je voulais faire ça :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
public static void replace(A oldA, A newA, List<A> listAs)
{
    listAs.Insert(listAs.IndexOf(oldA), newA);
    listAs.Remove(oldA);
}
Seulement avec ce code j'obtiens l'erreur de compilation suivante :
cannot convert from 'System.Collections.Generic.List<Appli.B>' to 'System.Collections.Generic.List<Appli.A>'
Si j'ai bien compris, cela vient du fait que List<T> n'est pas covariant (alors que IEnumerable<T> l'est...).
Cela dit, je comprends pas très bien pourquoi, surtout que j'ai réussi à m'en sortir autrement en utilisant les génériques :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
public static void foo<T>(T oldA, T newA, List<T> listAs)
  where T : A
{
    listAs.Insert(listAs.IndexOf(oldA), newA);
    listAs.Remove(oldA);
}
J'ai donc réussi à faire ce que je voulais faire, mais sans trop comprendre pourquoi. Pour moi les deux codes sont identiques...

Si quelqu'un pouvais m'éclairer.

Merci d'avance.