Digamos que tengo una clase
public class MyObject
{
public int SimpleInt{get;set;}
}
Y tengo un List<MyObject>
, y ToList()
lo cambio, y luego uno de los SimpleInt
, ¿se propagará mi cambio a la lista original? En otras palabras, ¿cuál sería el resultado del siguiente método?
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;
}
¿Por qué?
P / S: Lo siento si parece obvio averiguarlo. Pero no tengo compilador conmigo ahora ...
.ToList()
hace una copia superficial . Las referencias se copian, pero las nuevas referencias todavía apuntan a las mismas instancias a las que apuntan las referencias originales. Cuando lo piensas,ToList
no puedes crear ningunonew MyObject()
cuandoMyObject
es unclass
tipo.Respuestas:
Sí,
ToList
creará una nueva lista, pero como en este casoMyObject
es un tipo de referencia, la nueva lista contendrá referencias a los mismos objetos que la lista original.La actualización de la
SimpleInt
propiedad de un objeto al que se hace referencia en la nueva lista también afectará al objeto equivalente en la lista original.(Si
MyObject
se declarara como un enstruct
lugar de unclass
entonces, la nueva lista contendría copias de los elementos en la lista original, y la actualización de una propiedad de un elemento en la nueva lista no afectaría al elemento equivalente en la lista original).fuente
List
estructura,objectList[0].SimpleInt=5
no se permitiría una asignación como (error de tiempo de compilación de C #). Esto se debe a que el valor de retorno del descriptor deget
acceso de la lista no es una variable (es una copia devuelta de un valor de estructura) y, por lo tanto ,.SimpleInt
no está permitido establecer su miembro con una expresión de asignación (mutaría una copia que no se conserva) . Bueno, ¿quién usa estructuras mutables de todos modos?foreach (var s in listOfStructs) { s.SimpleInt = 42; }
. El problema realmente desagradable es cuando intentas algo comolistOfStructs.ForEach(s => s.SimpleInt = 42)
: el compilador lo permite y el código se ejecuta sin excepciones, ¡pero las estructuras en la lista permanecerán sin cambios!De la fuente Reflector'd:
Entonces, sí, su lista original no se actualizará (es decir, adiciones o eliminaciones), pero los objetos a los que se hace referencia lo harán.
fuente
ToList
siempre creará una nueva lista, que no reflejará ningún cambio posterior en la colección.Sin embargo, reflejará los cambios en los objetos mismos (a menos que sean estructuras mutables).
En otras palabras, si reemplaza un objeto en la lista original con un objeto diferente,
ToList
todavía contendrá el primer objeto.Sin embargo, si modifica uno de los objetos en la lista original,
ToList
seguirá conteniendo el mismo objeto (modificado).fuente
La respuesta aceptada aborda correctamente la pregunta del OP basada en su ejemplo. Sin embargo, solo se aplica cuando
ToList
se aplica a una colección concreta; no se mantiene cuando los elementos de la secuencia fuente aún no se han instanciado (debido a la ejecución diferida). En el caso de este último, puede obtener un nuevo conjunto de elementos cada vez que llameToList
(o enumere la secuencia).Aquí hay una adaptación del código del OP para demostrar este comportamiento:
Si bien el código anterior puede parecer artificial, este comportamiento puede aparecer como un error sutil en otros escenarios. Vea mi otro ejemplo para una situación en la que hace que las tareas se generen repetidamente.
fuente
Sí, crea una nueva lista. Esto es por diseño.
La lista contendrá los mismos resultados que la secuencia enumerable original, pero se materializó en una colección persistente (en memoria). Esto le permite consumir los resultados varias veces sin incurrir en el costo de volver a calcular la secuencia.
La belleza de las secuencias de LINQ es que son componibles. A menudo, lo
IEnumerable<T>
que obtiene es el resultado de combinar múltiples operaciones de filtrado, pedidos y / o proyección. Los métodos de extensión tienen gustoToList()
y leToArray()
permiten convertir la secuencia calculada en una colección estándar.fuente
Se crea una nueva lista, pero los elementos que contiene son referencias a los elementos originales (al igual que en la lista original). Los cambios en la lista en sí son independientes, pero los elementos encontrarán el cambio en ambas listas.
fuente
Simplemente me topé con este viejo post y pensé en agregar mis dos centavos. En general, si tengo dudas, uso rápidamente el método GetHashCode () en cualquier objeto para verificar las identidades. Entonces para arriba -
Y responde en mi máquina
Entonces, esencialmente, el objeto que lleva la lista permanece igual en el código anterior. Espero que el enfoque ayude.
fuente
Creo que esto es equivalente a preguntar si ToList hace una copia profunda o superficial. Como ToList no tiene forma de clonar MyObject, debe hacer una copia superficial, por lo que la lista creada contiene las mismas referencias que la original, por lo que el código devuelve 5.
fuente
ToList
creará una nueva lista.Si los elementos de la lista son tipos de valor, se actualizarán directamente, si son tipos de referencia, cualquier cambio se reflejará en los objetos a los que se hace referencia.
fuente
En el caso donde el objeto fuente es un verdadero IEnumerable (es decir, no solo una colección empaquetada como enumerable), ToList () NO puede devolver las mismas referencias de objeto que en el IEnumerable original. Devolverá una nueva lista de objetos, pero esos objetos pueden no ser iguales o incluso iguales a los objetos producidos por IEnumerable cuando se enumera nuevamente
fuente
Esto actualizará el objeto original también. La nueva lista contendrá referencias a los objetos que contiene, al igual que la lista original. Puede cambiar los elementos y la actualización se reflejará en el otro.
Ahora, si actualiza una lista (agregando o eliminando un elemento) que no se reflejará en la otra lista.
fuente
No veo en ninguna parte de la documentación que ToList () siempre tenga la garantía de devolver una nueva lista. Si un IEnumerable es una Lista, puede ser más eficiente verificar esto y simplemente devolver la misma Lista.
La preocupación es que a veces es posible que desee estar absolutamente seguro de que la Lista devuelta está! = A la Lista original. Debido a que Microsoft no documenta que ToList devolverá una nueva Lista, no podemos estar seguros (a menos que alguien haya encontrado esa documentación). También podría cambiar en el futuro, incluso si funciona ahora.
Se garantiza que la nueva lista (IEnumerable enumerablestuff) devolverá una nueva lista. Yo usaría esto en su lugar.
fuente
ToList
parece crear una nueva referencia de objeto de lista cuando se llama a unList
, BenB tiene razón cuando dice que esto no está garantizado por la documentación de MS.IEnumerable<>.ToList()
realidad se implementa comonew List<>(source)
y no hay una anulación específica paraList<>
, porList<>.ToList()
lo que devuelve una nueva referencia de objeto de lista. Pero una vez más, según la documentación de MS, no hay garantía de que esto no cambie en el futuro, aunque probablemente romperá la mayor parte del código.