ToList()— T-il Créer une Nouvelle Liste?
Disons que j'ai une classe
public class MyObject
{
public int SimpleInt{get;set;}
}
Et j'ai un List<MyObject>
, et je ToList()
puis modifier l'un des SimpleInt
, mon changement propager à la liste d'origine. En d'autres termes, ce serait la sortie de la méthode suivante?
public void RunChangeList()
{
var objs = new List<MyObject>(){new MyObject(){SimpleInt=0}};
var whatInt = ChangeToList(objs );
}
public int ChangeToList(List<MyObject> objects)
{
var objectList = objects.ToList();
objectList[0].SimpleInt=5;
return objects[0].SimpleInt;
}
Pourquoi?
P/S: je suis désolé si cela semble évident à trouver. Mais je n'ai pas de compilateur avec moi maintenant...
- Une façon de le phrasé, c'est que
.ToList()
fait un faible copier. Les références sont copiés, mais les nouvelles références pointent toujours vers le même cas que l'original de point de références. Quand vous pensez à elle,ToList
ne peut pas créer desnew MyObject()
quandMyObject
est unclass
type.
Vous devez vous connecter pour publier un commentaire.
Oui,
ToList
va créer une nouvelle liste, mais parce que, dans ce casMyObject
est un type de référence, puis la nouvelle liste contiendra des références pour les mêmes objets que la liste d'origine.La mise à jour de la
SimpleInt
propriété d'un objet référencé dans la nouvelle liste sera également affecter l'équivalent de l'objet dans la liste d'origine.(Si
MyObject
a été déclaré comme unstruct
plutôt qu'unclass
puis la nouvelle liste contient des copies des éléments dans la liste d'origine, et la mise à jour d'une propriété d'un élément dans la nouvelle liste pas affecter l'équivalent de l'élément dans la liste d'origine.)List
de structures, une assignation commeobjectList[0].SimpleInt=5
ne serait pas autorisé (C# erreur de compilation). C'est parce que la valeur de retour de la liste de l'indexeur estget
accesseur n'est pas une variable (c'est un retourné copie d'un struct valeur), et donc mise son membre.SimpleInt
avec une expression d'affectation n'est pas autorisé (il serait muter une copie qui n'est pas conservé). Eh bien, qui utilise les structures mutables de toute façon?foreach (var s in listOfStructs) { s.SimpleInt = 42; }
. Le vraiment méchant gotcha est lorsque vous essayez quelque chose commelistOfStructs.ForEach(s => s.SimpleInt = 42)
: le compilateur autorise et que le code s'exécute sans exceptions, mais leurs structures dans la liste va rester inchangé!Du Réflecteur avais source:
Donc oui, l'original de votre liste ne sera pas mis à jour (c'est à dire les ajouts ou suppressions) cependant les objets référencés.
ToList
toujours créer une nouvelle liste, qui ne sera pas refléter toute modification ultérieure à la collection.Cependant, il reflète les changements apportés aux objets eux-mêmes (Sauf s'ils sont mutables les structures).
En d'autres termes, si vous remplacez un objet dans la liste d'origine avec un autre objet, la
ToList
contient toujours le premier objet.Toutefois, si vous modifiez l'un des objets de la liste d'origine, le
ToList
contient toujours les mêmes (modifié) de l'objet.Oui, il crée une nouvelle liste. C'est par la conception.
La liste contiendra les mêmes résultats que l'original de la séquence énumérable, mais matérialisée dans un persistants (en mémoire) de la collection. Cela vous permet de consommer les résultats à plusieurs reprises, sans encourir le coût de recalculer la séquence.
La beauté de LINQ séquences, c'est qu'ils sont composables. Souvent, les
IEnumerable<T>
que vous obtenez est le résultat de la combinaison de plusieurs de filtrage, le tri et/ou des opérations de projection. Les méthodes d'Extension commeToList()
etToArray()
vous permettent de convertir le résultat de la séquence dans une collection standard.La accepté de répondre correctement les adresses de l'OP de la question en se basant sur son exemple. Cependant, il ne s'applique que lorsque
ToList
est appliqué sur un béton de la collection; il ne se pose pas lorsque les éléments de la séquence source doivent encore être instancié (en raison de l'exécution différée). Dans ce dernier cas, vous pourriez obtenir un nouvel ensemble d'éléments que chaque fois que vous appelezToList
(ou énumérer la séquence).Ici est une adaptation de l'OP de code pour illustrer ce comportement:
Alors que le code ci-dessus peut sembler artificiel, ce comportement peut apparaître comme un bug subtil dans d'autres scénarios. Voir mon autre exemple pour une situation où il provoque des tâches donné naissance à plusieurs reprises.
Une nouvelle liste est créée, mais les éléments sont des références à l'origine des éléments (comme dans l'original de la liste). Des modifications à la liste elle-même sont indépendants, mais les éléments trouverez le changement dans les deux listes.
Viens de tomber sur ce vieux post et de la pensée de l'ajout de mes deux cents. En général, si je suis dans le doute, j'ai rapidement à utiliser le GetHashCode() la méthode sur un objet quelconque pour vérifier les identités. Donc, pour ci -
Et de répondre sur ma machine -
Donc, essentiellement, l'objet qui comporte restent les mêmes dans le code ci-dessus. Espérons que la démarche permet de.
Je pense que c'est équivalent à demander si ToList n'est profonde ou peu profonde copie. Comme ToList n'a aucun moyen de cloner MyObject, il doit faire une copie superficielle, donc à la création de la liste contient les mêmes références que l'original, de sorte que le code renvoie 5.
ToList
permettra de créer une marque nouvelle liste.Si les éléments de la liste sont des types valeur, ils seront directement mis à jour, si elles sont des types référence, toute modification sera renvoyée dans les objets référencés.
Dans le cas où l'objet source est un vrai IEnumerable (c'est à dire pas seulement une collection emballé comme un énumérable), ToList() ne peut PAS renvoyer les mêmes références de l'objet comme dans l'original IEnumerable. Il sera de retour une nouvelle Liste d'objets, mais ces objets ne peuvent pas être les mêmes ou même Égale à la des objets produits par l'interface IEnumerable quand il est énuméré à nouveau
Cela permettra de mettre à jour l'objet d'origine en tant que bien. La nouvelle liste contient les références vers les objets qu'il contient, tout comme la liste d'origine. Vous pouvez modifier les éléments et la mise à jour sera reflétée dans l'autre.
Maintenant, si vous mettez à jour une liste (ajout ou suppression d'un élément) qui ne seront pas répercutées dans l'autre liste.
Je ne vois nulle part dans la documentation ToList() est la garantie de toujours renvoyer une nouvelle liste. Si un IEnumerable est une Liste, il peut être plus efficace pour vérifier cela et il suffit de retourner la même Liste.
Le souci est que parfois vous voulez être absolument sûr que la Liste retournée est != à la Liste d'origine. Parce que Microsoft n'a pas de document qui ToList sera de retour une nouvelle Liste, nous ne pouvons pas être sûr (à moins que quelqu'un a constaté que la documentation). Il pourrait également changer dans le futur, même si cela fonctionne maintenant.
nouvelle Liste(IEnumerable enumerablestuff) est garantie pour renvoyer une nouvelle Liste. Je voudrais utiliser ce lieu.
ToList
semble pour créer une nouvelle liste de référence de l'objet lorsqu'il est appelé sur uneList
, BenB a raison quand il dit que ce n'est pas garanti par MME de la documentation.IEnumerable<>.ToList()
est effectivement mis en œuvre commenew List<>(source)
et il n'est pas spécifique à surcharger pourList<>
, doncList<>.ToList()
, en effet, de retour d'une nouvelle liste de référence de l'objet. Mais encore une fois, comme par MS documentation, il n'y a aucune garantie de ne pas changer dans l'avenir, même s'il va à l'encontre de la plupart des code là-bas.