2013-05-16 20 views
14

Mam następujące zapytanie:Przypisywanie wartości w LINQ Select?

drivers.Select(d => { d.id = 0; d.updated = DateTime.Now; return d; }).ToList(); 

kierowcy to lista, która przychodzi z innym identyfikatorem i zaktualizowanej wartości, więc jestem zmianę wartości w wybór, ale to jest właściwy sposób to zrobić. Już wiem, że nie jestem realokacja sterowniki dla kierowców, ponieważ Resharper narzeka, więc myślę, że byłoby lepiej, gdyby to było:

drivers = drivers.Select(d => { d.id = 0; d.updated = DateTime.Now; return d; }).ToList(); 

ale jest to wciąż ten sposób ktoś powinien przypisać nowe wartości do każdego elementu w lista sterowników?

+0

możliwy duplikat [efektów ubocznych Linq] (http: // stackoverflow.com/questions/5632222/linq-side-effects) – nawfal

Odpowiedz

33

Chociaż wygląda to niewinnie, szczególnie w połączeniu z rozmową ToList, która natychmiast wykonuje kod, zdecydowanie trzymałbym się z dala od modyfikowania czegokolwiek w ramach zapytania: sztuczka jest tak niezwykła, że ​​wywołałaby czytelników twojego programu nawet doświadczeni, zwłaszcza, jeśli nigdy wcześniej tego nie widzieli.

Nie ma nic złego w foreach pętli - fakt, że może zrobić z LINQ, nie oznacza, że ​​powinny to robić.

+0

Użyłbym 'ForEach' dla instrukcji pojedynczej linii, a nie dla czegoś, co wymaga nawiasów klamrowych (wiele instrukcji). 'foreach' jest w rzeczywistości lepszy. – nawfal

+0

Masz rację, to mnie poturbowało :) Zgadzam się również z twoim drugim stwierdzeniem. – Xaisoft

+8

+1 LINQ nie powinien być używany do mutacji obiektu. – recursive

28

NIGDY NIE ZROBIĆ TEGO. Zapytanie powinno być zapytaniem ; powinno być nie destruktywnie zadając pytania źródła danych. Jeśli chcesz wywołać efekt uboczny, użyj pętli foreach; po to jest to. Użyj odpowiedniego narzędzia do zadania.

+4

Dziękuję Eric. Jedynym sposobem, aby poznać właściwą drogę, jest wiedzieć, że robisz to źle na pierwszym miejscu :) – Xaisoft

7

OK Sam sobie odpowiem.

Zapytania Xaisoft, Linq, czy to wyrażenie lambda, czy wyrażenie zapytania, nie powinny być używane do mutowania listy. W związku z tym Twój styl jest zły. To myli/nie da się odczytać, nie jest standardem i jest sprzeczne z filozofią Linq. Kolejna słaba styl osiągnięcia efekt końcowy jest:

drivers.Any(d => { d.id = 0; d.updated = DateTime.Now; return false; }); 

Ale to nie znaczy ForEach na List<T> jest niewłaściwe. Znajduje przypadki takie jak twoje, ale nie mieszaj mutacji z zapytaniem Linq, to wszystko. Wolę napisać coś w stylu:

drivers.ForEach(d => d.updated = DateTime.Now); 

Jest to elegancki i zrozumiały. Ponieważ nie zajmuje się Linq, nie jest również mylące. Nie lubię tej składni wielu zdań (jak w twoim przypadku) wewnątrz lambda. Jest trochę mniej czytelny i trudniejszy do debugowania, gdy rzeczy stają się skomplikowane. W twoim przypadku wolę prostą pętlę foreach.

foreach (var d in drivers) 
{ 
    d.id = 0; 
    d.updated = DateTime.Now; 
} 

Osobiście lubię ForEach na IEnumerable<T>as a terminating call to Linq expression (czyli jeśli zadanie nie ma być kwerendy ale egzekucja).

+0

Dzięki za dobre wyjaśnienie. – Xaisoft

+0

@ Xaisoft Właściwie to, czego nie lubię w 'ForEach' na' Liście 'jest fakt, że pojawiają się one domyślnie. Nie sądzę, żeby pasowało to do konstrukcji na poziomie struktury. Wolę takie konstrukty wyższego poziomu wchodzące według uznania użytkownika, jako rozszerzenie. Jeśli szyte na miarę produkty pomagają użytkownikowi końcowemu, idźmy na całość. Jest tam dużo maniaków i zależy od ludzi, czy ich produkcja pasuje czy nie. [Tu jest inny "switch-case" zaimplementowany dla 'Type',] (http://stackoverflow.com/a/1426626/661933) i jest świetny. Obejmij go lub odejdź. Nie dziwuj się temu ... – nawfal

+0

Kto się z tym śmieje i co to jest? – Xaisoft

Powiązane problemy