2012-02-03 8 views
12
string newName = "new name"; 

int[] numbers = new int[] { 1, 2, 3 }; 

var people = numbers.Select(n => new Person() 
{ 
    Name = n.ToString() 
}); 

foreach (var person in people) 
{ 
    person.Name = newName; 
} 

Debug.WriteLine(people.First().Name == newName); // returns false 

Spodziewałem się, że powyższa linia zwróci wartość true. Dlaczego nie mogę ustawić właściwości zmiennych iteracyjnych w pętli foreach?Dlaczego nie mogę ustawić właściwości zmiennych iteracyjnych w pętli foreach?

+3

duplikat: http://stackoverflow.com/questions/776430/why-is-the-iteration-variable-in-ac-sharp-foreach-statement-read-only –

+4

To nie jest ważne duplikat, nie chodzi o przypisanie do zmiennej pętli. Jest to problem opóźnionej realizacji. –

+0

@ M.Babcock Nie sądzę, że to duplikat pytania. pytanie w łączu próbuje przypisać do samej zmiennej iteracyjnej, podczas gdy moje pytanie przypisuje właściwość varaible iteracji. ale dzięki! – Yeonho

Odpowiedz

19

to definicja zapytania z odroczonym wykonaniem. Twoja foreach nad zapytaniem jest nieistotna, nie chodzi o niemożność ustawienia własności. Po wywołaniu First(), ponownie uruchamiasz zapytanie.

Dla jasności, definicja zapytania polega na tym, że dla elementów w liczbach utwórz nową osobę i przypisz wartość bieżącego elementu liczby do właściwości Nazwa osoby. Gdy wykonujesz iterację w pętli foreach, kwerenda ocenia i tworzysz nowe obiekty Person. Ale te obiekty Person nie są w zapytaniu, to tylko definicja! Ponowne uruchomienie kwerendy ponownie wykonuje definicję, tworzącróżne obiekty osób. Fakt, że zmodyfikowałeś oryginalne wyniki zapytania, nie ma wpływu na drugi zestaw wyników.

Jeśli chcieliby Państwo natychmiastowe wykonanie, użyj

var people = numbers.Select(n => new Person() 
    { 
     Name = n.ToString() 
    }).ToList(); 

Znajdziesz zmiany w przyklejania pętli, bo teraz people to konkretny wykaz zamiast definicji zapytania.

foreach (var person in people) 
{ 
    person.Name = newName; 
} 

Debug.WriteLine(people.First().Name.Equals(newName)); // returns true 
+0

oh ! Rozumiem. dzięki! – Yeonho

6

To jest doskonały przykład deferred execution.

Jeśli spróbujesz tego przykładu, działa tak, jak oczekujesz, ponieważ ToList wykonuje zapytanie.

string newName = "new name"; 

    int[] numbers = new int[] { 1, 2, 3 }; 

    var people = numbers.Select(n => new Person() 
    { 
     Name = n.ToString() 
    }).ToList(); // <===== here 

    foreach (var person in people) 
    { 
     person.Name = newName; 
    } 

    var b = people.First().Name == newName; 
Powiązane problemy