2012-07-31 21 views
8

Mam następujący scenariusz gdzie chcę dodać kilka elementów do listy ...List.AddRange z IEnumerable <T> parametr nie działa?

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

Używając tego kodu, żadnych przedmiotów są dodawane do listy, ale jeśli dodać .ToList() po czym LINQ oświadczenie to elementy są dodawane poprawnie. Przypuszczam, że jest to spowodowane odroczonym wykonywaniem, ale myślę, że biorąc pod uwagę funkcję List.AddRange akceptuje IEnumerable, że wyliczy elementy do dodania.

Czy ktoś może wyjaśnić, dlaczego tak się dzieje?

+0

To jest C#, prawda? – Antimony

+0

Przepraszam, tak C# (4.0) – John

+1

Jak widzisz "żadne przedmioty nie są dodawane", ponieważ powinien on dodawać przedmioty? –

Odpowiedz

2

Dzięki za odpowiedzi. Próbowałem uprościć kod dla tego przykładu, ale jak zwykle diabeł tkwi w szczegółach!

Pomiędzy instrukcją .Where() a wywołaniem funkcji AddRange() kod był (w głębi) usuwany z listy źródłowej ("elementy" w tym przykładzie). Deweloper nie zdawał sobie sprawy, że filtr został odroczony do czasu wywołania metody AddRange(), w którym to momencie usunięto listę źródeł.

Cieszę się, że nie straciłem fabuły :)

4

Przypuszczam, że jest to spowodowane odroczonym wykonaniem, ale pomyślałem, że biorąc pod uwagę funkcję List.AddRange akceptuje IEnumerable, że wyliczy elementy do dodania.

To robi. Występuje zwarcie dla ICollection<T> (którego nie uderzyłbyś w tym przypadku), co spowodowałoby użycie ICollection<T>.CopyTo zamiast wyliczania elementów, ale w przeciwnym razie wyliczy kolekcję.

Na przykład pracy, spróbuj:

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(); 
    } 
} 

ta wykorzystuje dokładną kod, a drukuje się 500 (właściwą liczbę elementów w List<T>).

+0

Może 'someCollection' w przykładzie OP jest jakiegoś typu, który zaimplementował' CopyTo' z pustą definicją? –

+0

@ DanTao Tak - możliwe, że dzieje się coś innego.Ale generalnie działa to poprawnie z 'IEnumerable ' - nie jest to problem "odroczonej realizacji". –

+0

@DanTao (Należy zauważyć, że wymagałoby to, aby OP posiadał własną metodę "Where", która tworzy "ICollection " z dziwną implementacją) –

1

To działa. Oto test jednostkowy, który to potwierdza:

[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); 
    } 
} 

Być może jest coś w twoim konkretnym scenariuszu, który nie działa poprawnie.

2

bym nie pomyślał, że dana funkcja List.AddRange akceptuje IEnumerable że byłoby wyliczyć elementów do dodania.

Próbowałem poniżej i AddRange(IEnumerable<T>) działa

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); 
Powiązane problemy