Comment puis-je caster un List<object>
Sur List<SomethingElse>
?
( où SomethingElse
est connu pour descendre de object
)
Bonus Chatter
Casting de la liste:
List<Object> first = ...;
List<SomethingElse> second = (List<SomethingElse>)first;
ne fonctionne pas:
Impossible de convertir le type 'System.Collections.Generic.List' en 'System.Collections.Generic.List'
Casting de la liste:
List<SomethingElse> second = first.Cast<SomethingElse>();
ne fonctionne pas:
Impossible de convertir implicitement le type 'System.Collections.Generic.List' en 'System.Collections.Generic.List'
je n'ai pas réellement besoin de l'objet List<T>
complet, juste un ICollection<T>
fera:
ICollection<SomethingElse> second = first;
ICollection<SomethingElse> second = (ICollection<SomethingElse>)first;
ICollection<SomethingElse> second = first.Cast<SomethingElse>();
ne marche pas.
LINQ, tel qu'implémenté via les méthodes d'extension de la classe Enumerable
, repose sur une exécution différée:
Les méthodes utilisées dans une requête qui renvoie une séquence de valeurs ne consomment pas les données cibles tant que l'objet de requête n'est pas énuméré. C'est ce qu'on appelle une exécution différée.
Cast<T>
ne crée pas une nouvelle liste immédiatement, mais stocke plutôt toutes les informations nécessaires à l'exécution de l'action. La liste ne serait énumérée que si nécessaire (par exemple, via une instruction foreach
).
Dans votre cas, si vous avez simplement l'intention d'itérer sur la séquence, vous devriez envisager de vous en tenir au IEnumerable<T>
interface, qui est le type de retour déclaré de Cast<T>
:
IEnumerable<SomethingElse> second = first.Cast<SomethingElse>();
foreach (SomethingElse se in second)
{
// ...
}
Ceci est efficace, car il effectue uniquement le cast à mesure que chaque élément est itéré.
Si vous êtes convaincu de vouloir créer une nouvelle liste immédiatement, utilisez ToList
:
List<SomethingElse> second = first.Cast<SomethingElse>().ToList();
Modifier : réponse au point publié dans le commentaire:
Cela dépend de ce que vous entendez par "une liste qui peut être modifiée". Il existe plusieurs opérateurs de requête LINQ qui vous permettront de modifier davantage la définition de votre requête. Par exemple, si vous souhaitez supprimer tous les éléments SomethingElse
dont la propriété IsDeleted
est true
, vous pouvez utiliser l'opérateur Where
:
IEnumerable<SomethingElse> second = first.Cast<SomethingElse>();
second = second.Where(element => !element.IsDeleted);
Si vous souhaitez ajouter une séquence de nouveaux éléments, vous pouvez utiliser l'opérateur Concat
:
second = second.Concat(anotherCollectionOfSomethingElse);
Si vous souhaitez trier votre séquence par ordre croissant de ID
, utilisez l'opérateur OrderBy
:
second = second.OrderBy(element => element.ID);
Chaque fois, nous appliquons un opérateur de requête sur l'ancienne définition de notre requête et affectons la nouvelle requête (composite) à notre variable second
. LINQ stockerait tous vos opérateurs dans la définition de la requête. Ensuite, lorsque la séquence est réellement énumérée (par exemple, via un foreach
ou ToList
), elle vous donnera le résultat composite de votre séquence, avec tous les opérateurs de requête appliqués dans l'ordre.
Comme pour tous les cas d'exécution différée/d'évaluation paresseuse, veillez à ne pas aller trop loin avec cela. Si, par exemple, vous allez appliquer un opérateur Where
qui réduira considérablement la taille de votre séquence, il pourrait être judicieux d'exécuter la requête avec impatience et de stocker la liste énumérée à la place.
Je pense que tu es proche avec le Cast<T>
expression. La différence est que Cast<T>
renvoie un IEnumerable<T>
, pas un List<T>
.
Essaye ça:
IEnumerable<SomethingElse> second = first.Cast<SomethingElse>();
Vous pouvez obtenir une liste en faisant quelque chose de similaire:
List<SomethingElse> second = first.Cast<SomethingElse>().ToList();
Vous avez la possibilité d'utiliser Cast
ou OfType
. Cast
lèvera une exception si vous ne pouvez pas convertir le type spécifié. OfType
d'autre part, ne renverra que les éléments de la liste qui peuvent être convertis en type spécifié. Je recommanderais d'utiliser OfType
dans votre situation.
List<Foo> fooList = myList.OfType<Foo>().ToList();