2016-08-17 15 views
5

Podczas korzystania z LINQ do zdefiniowania enumerable kolekcję, albo za pomocą metody rozszerzenie LINQ lub za pomocą operatorów zapytań aplikacja faktycznie nie budować kolekcję w tym czasie, że rozszerzenie LINQ metoda jest wykonywana; kolekcja jest wyliczana tylko wtedy, gdy iterujesz ją po . Oznacza to, że dane w oryginalnej kolekcji można zmieniać między wykonywaniem kwerendy LINQ a wyszukiwaniem danych identyfikujących kwerendę; zawsze będziesz pobierać najbardziej aktualne dane z .LINQ i ocena odroczony

Microsoft Visual C# 2013 krok po kroku napisane przez Johna Sharpa

Napisałem następujący kod:

List<int> numbers = new List<int>() { 1, 2, 3, 4, 5 }; 
IEnumerable<int> res = numbers.FindAll(a => a > 0).Select(b => b).ToList(); 
numbers.Add(99); 
foreach (int item in res) 
    Console.Write(item + ", "); 

Wynikiem powyższego kodu jest pokazany poniżej:

1, 2, 3, 4, 5,

Dlaczego to działa? Wiem o Func, Action i Predicate, ale nie mogę się dowiedzieć, co się tutaj dzieje. W oparciu o powyższą definicję kod nie jest racjonalny.

+1

Spróbuj usunąć 'ToList()' na końcu –

+0

@MatiasCicero Próbowałem, ale nie miałem żadnego efektu. – Media

+2

'ToList()' tworzy * nową * listę ('res') i kopiuje wszystkie elementy, ale dodajesz do * starej * jednej (' liczby') –

Odpowiedz

6

Oprócz ToList() na końcu, który tworzy nową kolekcję, masz inny problem.

Problem polega na tym, że w ogóle nie korzystasz z LINQ.

FindAll nie jest metodą rozszerzenia LINQ.

Należy użyć Where:

List<int> numbers = new List<int>() { 1, 2, 3, 4, 5 }; 
IEnumerable<int> res = numbers.Where(a => a > 0); 

numbers.Add(99); 

foreach (int item in res) 
    Console.Write(item + ", "); 
+3

To jest rzeczywisty sprawca i jedyna pełna odpowiedź. Całkowicie przeszedłem przez "FindAll". –

1

Zobaczysz wynik, którego się spodziewasz, jeśli odłożysz (lub usuniesz wszystko razem) operację ToList(), aż do pętli foreach. ToList wykona wyrażenie Linq tak samo jak wyliczanie.

List<int> numbers = new List<int>() { 1, 2, 3, 4, 5 }; 
IEnumerable<int> res = numbers.FindAll(a => a > 0).Select(b => b); 

numbers.Add(99); 

foreach (int item in res) 
    Console.Write(item + ", "); 

// another option, but not necessary in most cases... 
foreach (int item in res.ToList()) 
    Console.Write(item + ", "); 
+1

Nadal wypisuje '1, 2, 3, 4, 5,' –

+0

@GlennFerrie jak już wspomniałem w komentarzach, usunięcie ToList() nie tworzy odpowiedniej odpowiedzi, która powinna być zawarta 99. Próbowałem tego w Visual Studio 2013 i nie działa. – Media

2

Najpierw należy ustawić listę typu int, która zawiera 1,2,3,4,5. następnie użyłeś linq do stworzenia i zdefiniowania kolekcji wyliczeniowej. opisuje tutaj, jak działa linq: najpierw znajdź wszystkie liczby, które są większe od zera, ponieważ wszystkie pozycje na powyższej liście są większe od zera, a następnie zaznacz wszystkie i umieść je na liście. po dodaniu 99 do listy numerów nie ma ona wpływu na kolekcję wyliczeń, która została zdefiniowana, ponieważ utworzy nową kolekcję i przekaże jej elementy i nie będzie miała żadnych odniesień do listy numerów. można usunąć .ToList() na końcu wyrażenie linq, to ​​spowoduje: 1,2,3,4,5,99.

Powodzenia

+0

tak naprawdę nie martwisz się o ocenę negatywną. – Media

2

ToList tworzy nowy wystąpienie List<T> i skopiować wszystkie elementy do niego:

http://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs,e276d6892241255b

public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source) { 
    if (source == null) throw Error.ArgumentNull("source"); 
    return new List<TSource>(source); 
} 

Więc jeśli chcesz mieć 99 w res Ciebie należy dodać go do res, a nie do numbers:

... 
var res = numbers 
    .Where(a => a > 0) // Filter out; Select is redundant 
    .ToList(); 

res.Add(99); 

Console.Write(string.Join(", ", res)); 
2

ToList() rzeczywistości nie jest jedynym problemem. FindAll zwraca nową listę. Więc kiedy zadzwonisz

IEnumerable<int> res = numbers.FindAll(a => a > 0) 

To jest taka sama jak robi

IEnumerable<int> newList = new List<int>(); 
foreach (int old in numbers) { 
    if (old > 0) newList.Add(old); 
} 

więc po dodaniu nowego elementu do liczb, to już nie ma znaczenia. Przeszukujesz listę zwróconą przez FindAll zamiast z oryginalnej listy.