c# - visual - Impossible de convertir de la liste<DerivedClass> en liste<BaseClass>




visual studio 2017 generate documentation (4)

J'essaie de passer une liste de DerivedClass à une fonction qui prend une liste de BaseClass , mais j'obtiens l'erreur:

cannot convert from 
'System.Collections.Generic.List<ConsoleApplication1.DerivedClass>' 
to 
'System.Collections.Generic.List<ConsoleApplication1.BaseClass>'

Maintenant, je pourrais List<DerivedClass> ma List<DerivedClass> en une List<BaseClass> , mais je ne me sens pas à l’aise à moins de comprendre pourquoi le compilateur ne le permet pas.

Les explications que j'ai trouvées ont simplement dit que cela violait en quelque sorte la sécurité de type, mais je ne le vois pas. Quelqu'un peut m'aider?

Quel est le risque que le compilateur autorise la conversion de List<DerivedClass> en List<BaseClass> ?

Voici mon SSCCE:

class Program
{
    public static void Main()
    {
        BaseClass bc = new DerivedClass(); // works fine
        List<BaseClass> bcl = new List<DerivedClass>(); // this line has an error

        doSomething(new List<DerivedClass>()); // this line has an error
    }

    public void doSomething(List<BaseClass> bc)
    {
        // do something with bc
    }
}

class BaseClass
{
}

class DerivedClass : BaseClass
{
}

https://code.i-harness.com


Les explications que j'ai trouvées ont simplement dit que cela violait en quelque sorte la sécurité de type, mais je ne le vois pas. Quel est le risque que le compilateur autorise la conversion de List<DerivedClass> en List<BaseClass> ?

Cette question est posée presque tous les jours.

Une List<Mammal> ne peut pas être convertie en une List<Animal> car vous pouvez placer un lézard dans une liste d’animaux . Une List<Mammal > ne peut pas être convertie en une List<Giraffe> car il pourrait y avoir déjà un tigre dans la liste .

Par conséquent, List<T> doit être invariant dans T.

Cependant, List<Mammal> peut être converti en IEnumerable<Animal> (à partir de C # 4.0) car il n’existe aucune méthode sur IEnumerable<Animal> qui ajoute un lézard. IEnumerable<T> est covariant dans T.


C'est parce que List<T> est in-variant , pas co-variant , donc vous devriez changer pour IEnumerable<T> qui supporte le co-variant , ça devrait fonctionner:

IEnumerable<BaseClass> bcl = new List<DerivedClass>();
public void doSomething(IEnumerable<BaseClass> bc)
{
    // do something with bc
}

Informations sur la co-variante en générique


Lorsque vous avez une classe dérivée d'une classe de base, tous les conteneurs de ces classes ne sont pas automatiquement dérivés. Vous ne pouvez donc pas simplement lancer une List<Derived> dans une List<Base> .

Utilisez .Cast<T>() pour créer une nouvelle liste où chaque objet est renvoyé à la classe de base:

List<MyDerived> list1 = new List<MyDerived>();
List<MyBase> list2 = list1.Cast<MyBase>().ToList();

Notez qu'il s'agit d'une nouvelle liste, et non d'une version de distribution de votre liste d'origine. Les opérations sur cette nouvelle liste ne seront donc pas reflétées dans la liste d'origine. Les opérations sur les objets contenus refléteront cependant.


Si tu pouvais écrire

List<BaseClass> bcl = new List<DerivedClass>(); 

vous pourriez appeler

var instance = new AnotherClassInheritingFromBaseClass();
bc1.Add(instance);

Ajout d'une instance qui n'est pas une DerivedClass à la liste.







c#