2010-08-27 20 views
28

Esta es probablemente una pregunta básica para algunos, pero afecta la forma en que diseño una parte de mi programa.LINQ: la expresión Where devuelve una nueva instancia o referencia a la instancia del objeto

que tienen una única colección de tipo A:

IEnumerable<A> myCollection; 

estoy filtrando mi colección en 2 criterios diferentes:

IEnumerable<A> subCollection1 = myCollection.Where(x => x.Count > 10); 
etc. 

Ahora, sé que la expresión .Where devolverá una nueva instancia de IEnumerable, pero ¿la nueva colección contiene la misma referencia a una instancia de tipo A que 'myCollection' hace referencia, o son nuevas copias de tipo A creadas? Si se crean nuevas instancias de tipo 'A', ¿hay alguna manera de decir que 'subCollection1' hace referencia a las mismas instancias de A como referencias 'myCollection'?

Editar: Para añadir más aclaraciones.

Estoy buscando un modo para que cuando haga un cambio a una instancia de 'A' en 'subCollection1', también se modifique para 'myCollection'.

Respuesta

38

Las instancias son las mismas si son clases, pero copias si son estructuras/tipos de valores.

int, byte y double son value types, al igual que las estructuras (como System.Drawing.Point y las estructuras autodefinidas). Pero las cadenas, todas sus propias clases, básicamente "el resto", son reference types.

Nota: LINQ utiliza las mismas reglas que todas las demás asignaciones.

Para objetos:

Person p1 = new Person(); 
p1.Name = "Mr Jones"; 
Person p2 = p1; 
p2.Name = "Mr Anderssen"; 
// Now p1.Name is also "Mr Anderssen" 

Para estructuras:

Point p1 = new Point(); 
p1.x = 5; 
Point p2 = p1; 
p2.x = 10; 
// p1.x is still 5 

Las mismas reglas se aplican al uso de LINQ.

+0

eso es lo que yo había supuesto. Sólo quería asegurarse de que el caso de la expresión no estaba haciendo algún tipo de copia superficial en mis instancias de la clase. – Brandon

+1

a tener en cuenta que los tipos anónimos son siempre clases, así que también referencias. – Richard

+3

@Richard: También vale la pena señalar que el ty anónimo pes son inmutables en C# por lo que no puede modificar una instancia de tipo anónimo de todos modos. – LukeH

9

Son los mismos objetos. Where solo filtros, Select produce (puede producir) nuevas instancias.

2

Hacer un nuevo objeto que sea un tipo de referencia no es trivial. LINQ no tendría idea de cómo hacerlo. LINQ siempre devuelve las mismas instancias cuando se trata de tipos de referencia.

0

Solo quería agregar algunas de las otras respuestas; en general, cuando no estoy seguro de algo pero requiero un comportamiento en particular, agregaré una prueba unitaria para él. Podría poner esto fácilmente en una prueba y luego verificar la igualdad, lo que le indicará si está mirando una referencia del objeto en el contenedor original. Algunos pueden argumentar que esto es estúpido porque "deberían simplemente saber" lo que sucede, pero para mí sé que estaré 1) inseguro porque no soy un programador increíble, y 2) siempre hay noches en las que tengo que quemarme. el aceite de medianoche, y es bueno tener la seguridad de que algo se comporta como lo necesita.

+0

Esta pregunta se originó porque cuando tenía una colección que estaba filtrando usando la expresión Where, las Entidades de seguimiento automático de Entity Framework no se comportaban correctamente. Creo que el problema no se debe a mi incomprensión de cómo C# maneja las referencias, sino a un problema con el seguimiento que se apaga después de realizar la expresión Where. – Brandon

9

Actualmente depende de la colección. En algunos casos los métodos de Linq pueden devolver objetos clonados en lugar de referencias a los originales, echar un vistazo a esta prueba:

 [Test] 
    public void Test_weird_linq() 
    { 
     var names = new[]{"Fred", "Roman"}; 
     var list = names.Select(x => new MyClass() { Name = x }); 

     list.First().Name = "Craig"; 
     Assert.AreEqual("Craig", list.First().Name);    
    } 

    public class MyClass 
    { 
     public string Name { get; set; } 
    } 

Esta prueba va a fracasar, a pesar de que muchas personas creen que el mismo objeto será devuelto en su "lista.En primer lugar()", pero funcionará si se utiliza otra colección 'modificado con ToList()'

var list = names.Select(x => new MyClass() { Name = x }).ToList(); 

No sé a ciencia cierta por qué funciona de esta manera, pero es algo a tener en cuenta cuando se escribir el código :)

puede ayudar a entender How LINQ works internally

Cuestiones relacionadas