207 votes

Convertir Liste<DerivedClass> à la Liste<BaseClass>

Alors que nous pouvons hériter de la classe de base/interface, pourquoi ne pouvons-nous déclarer List<> en utilisant la même classe ou interface?

interface A
{ }
    class B : A
    { }
        class C : B
        { }

class Test
{
    static void Main(string[] args)
    {
        A a = new C(); // OK
        List<A> listOfA = new List<C>(); // compiler Error
    }
}

Est-il un moyen de contourner?

265voto

Mark Byers Points 318575

La façon de faire de ce travail est d'itérer sur la liste et jeté les éléments. Cela peut être fait en utilisant ConvertAll:

List<A> listOfA = new List<C>().ConvertAll(x => (A)x);

Vous pouvez également utiliser Linq:

List<A> listOfA = new List<C>().Cast<A>().ToList();

180voto

Eric Lippert Points 300275

Tout d'abord, cessez de l'utiliser, impossible à comprendre les noms de classe A, B, C. l'Utilisation des Animaux, des Mammifères, des Girafes, ou de la Nourriture, des Fruits, à l'Orange ou quelque chose où les relations sont claires.

Votre question est "pourquoi je ne peux pas attribuer une liste de girafes à une variable de type liste de l'animal, depuis que je peux attribuer une girafe à une variable de type animal?"

La réponse est: supposons que vous pourriez. Ce qui pourrait alors aller mal?

Eh bien, vous pouvez ajouter un Tigre à une liste d'animaux. Supposons que nous vous permettons de mettre une liste de girafes dans une variable qui contient une liste d'animaux. Ensuite, vous essayez d'ajouter un tigre à cette liste. Ce qui se passe? Voulez-vous la liste des girafes pour contenir un tigre? Voulez-vous un crash? ou voulez-vous le compilateur pour vous protéger de l'accident par l'affectation illégale en premier lieu?

Nous avons choisi la dernière.

Ce type de conversion est appelé un "covariant" la conversion. En C# 4, nous allons vous permettre de faire des covariants des conversions sur les interfaces et les délégués lors de la conversion est connu pour être toujours en sécurité. Voir mes articles de blog sur la covariance et la contravariance pour plus de détails. (Il y aura un frais un sur ce sujet sur deux le lundi et le jeudi de cette semaine).

31voto

Chris Pitman Points 5981

Aussi loin que pourquoi ça ne fonctionne pas, il peut être utile de comprendre la covariance et la contravariance.

Juste pour montrer pourquoi cela ne devrait pas travailler, ici, c'est un changement du code que vous avez fournies:

void DoesThisWork()
{
     List<C> DerivedList = new List<C>();
     List<A> BaseList = DerivedList;
     BaseList.Add(new B());

     C FirstItem = DerivedList.First();
}

Si cela fonctionne? Le Premier élément de la liste est de Type "B", mais le type de la DerivedList élément est C.

Maintenant, supposons que nous avons vraiment veux juste faire une fonction générique qui fonctionne sur une liste d'un genre qui met en œuvre, mais nous ne se soucient pas de ce type:

void ThisWorks<T>(List<T> GenericList) where T:A
{

}

void Test()
{
     ThisWorks(new List<B>());
     ThisWorks(new List<C>());
}

0voto

Noon Silk Points 30396

Parce que le C# n'autorise pas ce type d' héritage de conversion pour le moment.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X