Syntaxe plus courte pour le moulage à partir d'une Liste<X> une Liste<Y>?
Je sais que c'est possible de lancer une liste d'éléments d'un type à l'autre (étant donné que votre objet a un public static explicite de l'opérateur méthode pour faire le casting, un à la fois, comme suit:
List<Y> ListOfY = new List<Y>();
foreach(X x in ListOfX)
ListOfY.Add((Y)x);
Mais n'est-il pas possible de jeter de l'ensemble de la liste en une seule fois? Par exemple,
ListOfY = (List<Y>)ListOfX;
- J'ai juste essayé de faire un peu plus clair. Ne vous inquiétez pas, vous n'êtes pas, je comprends 🙂
- En supposant X dérive de Y, et Z dérive de Y, pensez à ce qui pourrait arriver si vous Z ajoutées à votre Liste<Y> qui est vraiment une Liste<X>.
InformationsquelleAutor Jimbo | 2011-02-25
Vous devez vous connecter pour publier un commentaire.
Si
X
peut vraiment être jeté àY
vous devriez être en mesure d'utiliserCertaines choses pour être au courant de (H/T pour les commentateurs!)
using System.Linq;
d'obtenir cette extension de la méthodeList<Y>
sera créé par l'appel àToList()
.Cast<T>
méthode ne prend pas en charge personnalisée opérateurs de conversion. Pourquoi le Linq Cast Helper fonctionne Pas Avec l'Implicite de l'Opérateur de Cast.Directe de la fonte
var ListOfY = (List<Y>)ListOfX
n'est pas possible, car cela exigerait co/contravariance de laList<T>
type, et que tout ne peut pas être garantie dans tous les cas. Veuillez lire la suite pour voir les solutions à ce casting problème.Alors qu'il semble normal d'être capable d'écrire du code comme ceci:
parce que nous pouvons garantir que tous les mammifères seront un animal, ce qui est évidemment une erreur:
depuis pas chaque animal est un mammifère.
Cependant, à l'aide de C# 3 et ci-dessus, vous pouvez utiliser
qui facilite le casting un peu. C'est syntaxiquement équivalent à celui de votre un par un ajout de code, car il utilise un cast explicite cast chaque
Mammal
dans la liste à unAnimal
, et échoue si le casting n'est pas réussi.Si vous voulez plus de contrôle sur la coulée /le processus de conversion, vous pouvez utiliser le
ConvertAll
méthode de laList<T>
classe, qui peut utiliser une expression à convertir les éléments. Il a ajouté l'avantage qu'il renvoie uneList
, au lieu deIEnumerable
, donc pas de.ToList()
est nécessaire.À ajouter à Sweko point:
La raison pour laquelle la fonte
n'est pas possible que parce que le
List<T>
est invariant dans le Type T et donc il n'a pas d'importance siX
dérive deY
) - c'est parce queList<T>
est défini comme:(À noter que dans la présente déclaration, type
T
ici n'a pas de variance supplémentaire modificateurs)Toutefois, si mutable collections ne sont pas nécessaires dans votre conception, une sortie sur un grand nombre de immuable collections, est possible, par exemple, à condition que
Giraffe
dérive deAnimal
:C'est parce que
IEnumerable<T>
prend en charge la covariance dansT
- ce qui est logique étant donné queIEnumerable
implique que la collection ne peut pas être modifié, car il n'a pas de support pour les méthodes pour Ajouter ou Supprimer des éléments de la collection. Remarque leout
mot-clé dans la déclaration deIEnumerable<T>
:(Voici plus d'explications pour la raison pour laquelle mutable collections comme
List
ne peut pas soutenircovariance
, alors que immuables itérateurs et des collections.)Casting avec
.Cast<T>()
Comme d'autres l'ont mentionné,
.Cast<T>()
peut être appliquée à une collection pour projet une nouvelle collection d'éléments coulé à T, cependant cela permettra de jeter unInvalidCastException
si la fonte sur un ou plusieurs éléments n'est pas possible (ce qui serait le même comportement que le fait de faire le cast explicite dans le cas des OPforeach
boucle).De filtrage et de Casting avec
OfType<T>()
Si l'entrée de la liste contient des éléments différents, incompatibles types, le potentiel
InvalidCastException
peut être évité en utilisant.OfType<T>()
au lieu de.Cast<T>()
. (.OfType<>()
vérifie si un élément peut être convertie dans le type de cible, avant de tenter la conversion, et de filtrer les types incompatibles.)foreach
Notez également que si l'OP a écrit ceci à la place: (notez le explicite
Y y
dans leforeach
)que le casting sera tentée. Toutefois, si aucune conversion n'est possible, un
InvalidCastException
sera le résultat.Exemples
Par exemple, pour la simple (C#6) hiérarchie de classe:
Lorsque l'on travaille avec une collection de différents types:
Considérant ce qui suit:
filtre uniquement les Éléphants - c'est à dire les Zèbres sont éliminés.
Re: opérateurs de transtypage Implicite
Sans dynamique, défini par l'utilisateur opérateurs de conversion sont également utilisés lors de la au moment de la compilation*, de sorte que même si un opérateur de conversion entre le Zèbre et l'Éléphant a été mis à disposition, le moment de l'exécution du comportement des approches de conversion ne change pas.
Si l'on ajoute un opérateur de conversion pour convertir un Zèbre, un Éléphant:
Au lieu de cela, compte tenu de la ci-dessus opérateur de conversion, le compilateur sera en mesure de changer le type du tableau ci-dessous à partir de
Animal[]
àElephant[]
, étant donné que les Zèbres peuvent être convertis en un tout homogène collection d'Éléphants:Aide de la Conversion Implicite des Opérateurs au moment de l'exécution
*Comme mentionné par Eric, l'opérateur de conversion peut cependant être consulté au moment de l'exécution par le recours à
dynamic
:foreach
ne filtre pas, mais à l'aide d'une dérivée type que la variable d'itération va forcer le compilateur à la tentative d'un plâtre, qui échoue sur le premier élément qui n'est pas conforme.Vous pouvez utiliser
List<Y>.ConvertAll<T>([Converter from Y to T]);
Ce n'est pas tout à fait la réponse à cette question, mais il peut être utile pour certains: comme @SWeko dit, grâce à la covariance et la contravariance,
List<X>
ne peut pas être jeté dansList<Y>
, maisList<X>
peut être jeté dansIEnumerable<Y>
, et même avec un cast implicite.Exemple:
mais
Le gros avantage de ne pas créer une nouvelle liste dans la mémoire.