c# - query - ToList()-¿Crea una nueva lista?
linq c# tutorial español (12)
Digamos que tengo una clase
public class MyObject
{
public int SimpleInt{get;set;}
}
Y tengo un List<MyObject>
y I ToList()
y luego cambio uno de SimpleInt
, mi cambio se propagará nuevamente 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 ...
Acabo de tropezar con esta publicación anterior y pensé en agregar mis dos centavos. Generalmente, si tengo dudas, rápidamente uso el método GetHashCode () en cualquier objeto para verificar las identidades. Entonces para arriba -
public class MyObject
{
public int SimpleInt { get; set; }
}
class Program
{
public static void RunChangeList()
{
var objs = new List<MyObject>() { new MyObject() { SimpleInt = 0 } };
Console.WriteLine("objs: {0}", objs.GetHashCode());
Console.WriteLine("objs[0]: {0}", objs[0].GetHashCode());
var whatInt = ChangeToList(objs);
Console.WriteLine("whatInt: {0}", whatInt.GetHashCode());
}
public static int ChangeToList(List<MyObject> objects)
{
Console.WriteLine("objects: {0}", objects.GetHashCode());
Console.WriteLine("objects[0]: {0}", objects[0].GetHashCode());
var objectList = objects.ToList();
Console.WriteLine("objectList: {0}", objectList.GetHashCode());
Console.WriteLine("objectList[0]: {0}", objectList[0].GetHashCode());
objectList[0].SimpleInt = 5;
return objects[0].SimpleInt;
}
private static void Main(string[] args)
{
RunChangeList();
Console.ReadLine();
}
Y responde en mi máquina -
- objs: 45653674
- objs [0]: 41149443
- objetos: 45653674
- objetos [0]: 41149443
- objectList: 39785641
- objectList [0]: 41149443
- whatInt: 5
Entonces, esencialmente, el objeto que lleva la lista sigue siendo el mismo en el código anterior. Espero que el enfoque ayude.
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.
De la fuente reflejada:
public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source)
{
if (source == null)
{
throw Error.ArgumentNull("source");
}
return new List<TSource>(source);
}
Entonces, sí, su lista original no se actualizará (es decir, adiciones o eliminaciones), sin embargo, los objetos a los que se hace referencia lo harán.
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 que los objetos producidos por IEnumerable cuando se enumeran de nuevo.
La respuesta aceptada aborda correctamente la pregunta del OP en función de su ejemplo. Sin embargo, solo se aplica cuando ToList
se aplica a una colección concreta; no se cumple cuando los elementos de la secuencia de origen 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 llame a ToList
(o enumere la secuencia).
Aquí hay una adaptación del código de OP para demostrar este comportamiento:
public static void RunChangeList()
{
var objs = Enumerable.Range(0, 10).Select(_ => new MyObject() { SimpleInt = 0 });
var whatInt = ChangeToList(objs); // whatInt gets 0
}
public static int ChangeToList(IEnumerable<MyObject> objects)
{
var objectList = objects.ToList();
objectList.First().SimpleInt = 5;
return objects.First().SimpleInt;
}
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 provoca que las tareas se engendren repetidamente.
No veo en ninguna parte de la documentación que ToList () siempre garantice la devolución de 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 es! = 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 (I enumerable enumerabletuff) devuelva una nueva lista. Yo usaría esto en su lugar.
Sí, ToList
creará una nueva lista, pero como en este caso MyObject
es un tipo de referencia, la nueva lista contendrá referencias a los mismos objetos que la lista original.
La actualización de la propiedad SimpleInt
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 declaró como una struct
lugar de una class
, 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).
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 artículos encontrarán el cambio en ambas listas.
ToList siempre creará una nueva lista, que no reflejará ningún cambio posterior en la colección.
Sin embargo, reflejará 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
aún contendrá el primer objeto.
Sin embargo, si modifica uno de los objetos en la lista original, ToList
aún contendrá el mismo objeto (modificado).
ToList
creará una nueva lista.
Si los elementos de la lista son tipos de valor, se actualizarán directamente, si son tipos de referencia, los cambios se reflejarán nuevamente en los objetos a los que se hace referencia.
Sí, crea una nueva lista. Esto es por diseño.
La lista contendrá los mismos resultados que la secuencia enumerable original, pero se materializará 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 LINQ es que son compostables. A menudo, el IEnumerable<T>
que obtienes es el resultado de combinar múltiples operaciones de filtrado, ordenamiento y / o proyección. Los métodos de extensión como ToList()
y ToArray()
permiten convertir la secuencia calculada en una colección estándar.
var objectList = objects.ToList();
objectList[0].SimpleInt=5;
Esto también actualizará el objeto original. 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) eso no se reflejará en la otra lista.