Je veux faire quelque chose comme ça:
List<Child> childList = new List<Child>();
...
List<Parent> parentList = childList;
Cependant, parce que parentList est un Liste de l'ancêtre de l'enfant, plutôt qu'un ancêtre direct, je suis incapable de le faire. Existe-t-il une solution de contournement (autre que l'ajout de chaque élément individuellement)?
Le casting direct n'est pas autorisé car il n'y a aucun moyen de le rendre dactylographié. Si vous avez une liste de girafes et que vous la définissez sur une liste d'animaux, vous pouvez alors ajouter un tigre à une liste de girafes! Le compilateur ne vous arrêterait pas, car bien sûr, un tigre peut entrer dans une liste d'animaux. Le compilateur ne peut vous arrêter que lors de la conversion non sécurisée.
En C # 4, nous allons prendre en charge la covariance et la contravariance des interfaces SAFE et des types de délégués paramétrés avec des types de référence. Voir ici pour plus de détails:
http://blogs.msdn.com/ericlippert/archive/tags/Covariance+and+Contravariance/default.aspx
Utiliser LINQ:
List<Parent> parentList = childList.Cast<Parent>().ToList();
En 2009, Eric nous a dit que les choses changeraient en C # 4. Où en sommes-nous aujourd'hui?
Les classes utilisées dans ma réponse se trouvent au bas de la page. Pour faciliter la tâche, nous utiliserons une classe Mammal
comme "parent" et les classes Cat
et Dog
comme des "enfants". Les chats et les chiens sont deux mammifères. , mais un chat n’est pas un chien et un chien n’est pas un chat.
Ce n'est toujours pas légal, et ne peut pas être:
List<Cat> cats = new List<Cat>();
List<Mammal> mammals = cats;
Pourquoi pas? Les chats sont des mammifères, alors pourquoi ne pouvons-nous pas attribuer une liste de chats à un List<Mammal>
?
Parce que si nous étions autorisés à stocker une référence à un List<Cat>
dans une variable List<Mammal>
, nous serions alors en mesure de compiler le code suivant pour ajouter un chien à une liste de chats:
mammals.Add(new Dog());
Nous ne devons pas permettre cela! Rappelez-vous, mammals
est simplement une référence à cats
. Dog
ne descend pas de Cat
et n'a pas d'activité dans une liste d'objets Cat
.
À partir de .NET Framework 4 , plusieurs interfaces génériques ont des paramètres de type covariant déclarés avec le mot clé out
Generic Modifier introduit en C # 4. Parmi ces interfaces, on trouve IEnumerable<T>
qui est bien sûr implémenté par List<T>
.
Cela signifie que nous can allons maintenant convertir un List<Cat>
en IEnumerable<Mammal>
:
IEnumerable<Mammal> mammalsEnumerable = cats;
Nous ne pouvons pas ajouter un nouveau Dog
à mammalsEnumerable
car IEnumerable<out T>
est une interface "en lecture seule", c’est-à-dire qu’il n’a pas de méthode Add()
, mais nous peut utilisons maintenant cats
partout où un IEnumerable<Mammal>
peut être utilisé. Par exemple, nous pouvons concaténer mammalsEnumerable
avec un List<Dog>
pour renvoyer une nouvelle séquence:
void Main()
{
List<Cat> cats = new List<Cat> { new Cat() };
IEnumerable<Mammal> mammalsEnumerable =
AddDogs(cats); // AddDogs() takes an IEnumerable<Mammal>
Console.WriteLine(mammalsEnumerable.Count()); // Output: 3. One cat, two dogs.
}
public IEnumerable<Mammal> AddDogs(IEnumerable<Mammal> parentSequence)
{
List<Dog> dogs = new List<Dog> { new Dog(), new Dog() };
return parentSequence.Concat(dogs);
}
Définitions de classe:
public abstract class Mammal { }
public class Cat: Mammal { }
public class Dog : Mammal { }
oui, tu peux le faire comme
var result = List.And(x => x.Parent.All(b => b.ParentId == value));