2012-07-31 79 views
8

tengo el siguiente escenario donde quiero añadir algunos elementos a una lista ...List.AddRange con el parámetro IEnumerable <T> ¿no funciona?

List<T> items = new List<T>(); 
IEnumerable<T> addItems = someCollection.Where(...); 
items.AddRange(addItems); 

Usando este código, no hay ningún elemento añadido a la lista, pero si añado un .ToList() después de entonces LINQ declaración luego los elementos se agregan correctamente. Supongo que esto se debe a la ejecución diferida, pero habría pensado que, dada la función List.AddRange, acepta un IEnumerable que enumeraría los elementos que se agregarán.

¿Puede alguien aclarar por qué sucede esto?

+0

Esto es C#, ¿verdad? – Antimony

+0

Lo sentimos, sí C# (4.0) – John

+1

¿Cómo se está viendo "no se añaden elementos" los, porque debe agregar elementos? –

Respuesta

2

Gracias por las respuestas. Traté de simplificar el código para este ejemplo, pero como de costumbre, ¡el diablo está en los detalles!

Entre la declaración .Where() y el AddRange() llama el código era (en el fondo) la limpieza de la fuente ('artículos' en este ejemplo) lista. El desarrollador no se dio cuenta de que el filtro se aplazó hasta la llamada AddRange(), en cuyo momento ya habían borrado la lista de origen.

Me alegra saber que no he perdido la trama :)

4

Supongo que esto se debe a la ejecución diferida, pero habría pensado que dada la función List.AddRange acepta un IEnumerable que enumeraría los elementos que se agregarán.

Lo hace. Hay un cortocircuito para ICollection<T> (que no tocaría en este caso), lo que provocaría que usara ICollection<T>.CopyTo en lugar de enumerar los elementos, pero de lo contrario, enumerará la colección.

Para un ejemplo de trabajo, poner en práctica:

using System; 
using System.Linq; 
using System.Collections.Generic; 

internal class Program 
{ 
    private static List<T> RunQuery<T>(IEnumerable<T> someCollection, Func<T, bool> predicate) 
    { 
     List<T> items = new List<T>(); 
     IEnumerable<T> addItems = someCollection.Where(predicate); 
     items.AddRange(addItems); 
     return items; 
    } 

    static void Main() 
    { 
     var values = Enumerable.Range(0, 1000); 

     List<int> results = RunQuery(values, i => i >= 500); 

     Console.WriteLine(results.Count); 
     Console.WriteLine("Press key to exit:"); 
     Console.ReadKey(); 
    } 
} 

Este utiliza el código exacto, y se imprimirá 500 (el número apropiado de elementos de la List<T>).

+0

'someCollection' en el ejemplo de la OP es de algún tipo que ha implementado' CopyTo' con una definición vacía? –

+0

@DanTao Sí, es posible que algo más esté sucediendo.Pero, en general, esto funciona correctamente con 'IEnumerable ' - no es un problema de "ejecución diferida". –

+0

@DanTao (Tenga en cuenta que requeriría que el OP tenga su propio método "Where" que cree el 'ICollection ' con una implementación extraña) –

1

Funciona. Aquí está una prueba de unidad que lo demuestra:

[TestFixture] 
public class AddRangeTest 
{ 
    [Test] 
    public void AddRange() 
    { 
     var list = new List<int>(); 
     var someCollection = new List<int> { 1, 2, 3 }; 
     var subItems = someCollection.Where(x => x > 1); 
     list.AddRange(subItems); 
     Assert.AreEqual(2, list.Count); 
    } 
} 

Tal vez hay algo en su escenario específico que no está funcionando correctamente.

2

Hubiera pensado que, dada la función List.AddRange, acepta un IEnumerable que enumeraría los elementos que se agregarán.

Probé la continuación y AddRange(IEnumerable<T>) no trabajar

List<string> someCollection = new List<string>{"A", "B", "C"}; 
List<string> items = new List<string>(); 
IEnumerable<string> addItems = someCollection.Where(x => x != ""); 
items.AddRange(addItems); 
Cuestiones relacionadas