Je sais qu'il est possible de caster une liste d'éléments d'un type à un autre (étant donné que votre objet a une méthode d'opérateur explicite statique publique 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 lancer la liste entière en une seule fois? Par exemple,
ListOfY = (List<Y>)ListOfX;
c#
list
casting
ienumerable
Jimbo
la source
la source
Réponses:
Si vous
X
pouvez vraiment vous lancer,Y
vous devriez pouvoir utiliserQuelques choses à savoir (H / T aux commentateurs!)
using System.Linq;
pour obtenir cette méthode d'extensionList<Y>
sera créé par l'appel àToList()
.la source
Cast<T>
méthode ne prend pas en charge les opérateurs de conversion personnalisés. Pourquoi le Linq Cast Helper ne fonctionne-t-il pas avec l'opérateur de transfert implicite ?La conversion directe
var ListOfY = (List<Y>)ListOfX
n'est pas possible car elle nécessiterait une co / contravariance duList<T>
type, et cela ne peut tout simplement pas être garanti dans tous les cas. Veuillez lire la suite pour voir les solutions à ce problème de casting.Bien qu'il semble normal de pouvoir écrire du code comme ceci:
parce que nous pouvons garantir que chaque mammifère sera un animal, c'est évidemment une erreur:
car tous les animaux ne sont pas des mammifères.
Cependant, en utilisant C # 3 et supérieur, vous pouvez utiliser
cela facilite un peu le casting. Ceci est syntaxiquement équivalent à votre code d'ajout un par un, car il utilise une conversion explicite pour convertir chaque élément
Mammal
de la liste en unAnimal
, et échouera si la conversion n'est pas réussie.Si vous aimez plus de contrôle sur le processus de transtypage / conversion, vous pouvez utiliser la
ConvertAll
méthode de laList<T>
classe, qui peut utiliser une expression fournie pour convertir les éléments. Il a l'avantage supplémentaire de renvoyer unList
, au lieu deIEnumerable
, donc aucun.ToList()
n'est nécessaire.la source
Pour ajouter au point de Sweko:
La raison pour laquelle le casting
n'est pas possible parce que le
List<T>
est invariant dans le Type T et donc peu importe qu'ilX
dérive deY
) - c'est parce queList<T>
est défini comme:(Notez que dans cette déclaration, le type
T
ici n'a pas de modificateurs de variance supplémentaires)Cependant, si des collections modifiables ne sont pas requises dans votre conception, une conversion ascendante sur un grand nombre des collections immuables est possible , par exemple à condition qu'elles
Giraffe
dérivent deAnimal
:En effet,
IEnumerable<T>
prend en charge la covariance dansT
- cela a du sens étant donné qu'ilIEnumerable
implique que la collection ne peut pas être modifiée, car elle ne prend pas en charge les méthodes pour ajouter ou supprimer des éléments de la collection. Notez leout
mot - clé dans la déclaration deIEnumerable<T>
:( Voici une explication supplémentaire de la raison pour laquelle les collections mutables comme
List
ne peuvent pas prendre en chargecovariance
, alors que les itérateurs et les collections immuables le peuvent.)Casting avec
.Cast<T>()
Comme d'autres l'ont mentionné,
.Cast<T>()
peut être appliqué à une collection pour projeter une nouvelle collection d'éléments castés en T, mais cela provoquera un jetInvalidCastException
si la cast sur un ou plusieurs éléments n'est pas possible (ce qui serait le même comportement que de faire l'explicite dans laforeach
boucle de l'OP ).Filtrage et diffusion avec
OfType<T>()
Si la liste d'entrée contient des éléments de types différents et incompatibles, le potentiel
InvalidCastException
peut être évité en utilisant à la.OfType<T>()
place de.Cast<T>()
. (.OfType<>()
vérifie si un élément peut être converti en type cible, avant de tenter la conversion, et filtre les types incompatibles.)pour chaque
Notez également que si l'OP l'a écrit à la place: (notez l' explicite
Y y
dans leforeach
)que le casting sera également tenté. Cependant, si aucun lancer n'est possible, un
InvalidCastException
résultat sera obtenu.Exemples
Par exemple, étant donné la hiérarchie de classe simple (C # 6):
Lorsque vous travaillez avec une collection de types mixtes:
Tandis que:
filtre uniquement les éléphants - c'est-à-dire que les zèbres sont éliminés.
Re: opérateurs de distribution implicites
Sans opérateurs de conversion dynamiques définis par l'utilisateur, ils ne sont utilisés qu'au moment de la compilation *, donc même si un opérateur de conversion entre Zebra et Elephant, par exemple, était disponible, le comportement d'exécution des approches de conversion ci-dessus ne changerait pas.
Si nous ajoutons un opérateur de conversion pour convertir un zèbre en éléphant:
Au lieu de cela, étant donné l'opérateur de conversion ci-dessus, le compilateur pourra changer le type du tableau ci-dessous de
Animal[]
àElephant[]
, étant donné que les zèbres peuvent maintenant être convertis en une collection homogène d'éléphants:Utilisation d'opérateurs de conversion implicite lors de l'exécution
* Comme mentionné par Eric, l'opérateur de conversion est cependant accessible au moment de l'exécution en recourant à
dynamic
:la source
foreach
ne filtre pas, mais l'utilisation d'un type plus dérivé comme variable d'itération contraindra le compilateur à tenter une conversion, qui échouera sur le premier élément non conforme.Vous pouvez utiliser
List<Y>.ConvertAll<T>([Converter from Y to T]);
la source
Ce n'est pas tout à fait la réponse à cette question, mais cela peut être utile pour certains: comme @SWeko l'a dit, grâce à la covariance et à la contravariance,
List<X>
ne peut pas être intégréList<Y>
, maisList<X>
peut être intégré àIEnumerable<Y>
, et même avec une implicite.Exemple:
mais
Le gros avantage est qu'il ne crée pas de nouvelle liste en mémoire.
la source
la source