2016-06-23 3 views
3

Я столкнулся с (для меня) странным поведением. Вот код:Является ли Linq-Query вызванным toList(), генерирующим копии содержащихся элементов?

var objects = from i in items 
       //some calculations 
       select something; 

// other calculations 

objects.ToList().ForEach(x => { 
    //some calculations 
    x.Property = "some text" 
}); 

return objects; 

Сначала я генерировать IEnumerable, это запрос к БД, я пропустил детали. Затем я должен выполнить другие вычисления, и в конце я перебираю мои объекты, чтобы задать еще один параметр. Запустив этот код, как только объекты IEnumerable будут возвращены, их Property не установлен.

В противном случае, если я двигаю ToList() в выражении Linq, как последовавший Property установлен:

var objects = (from i in items 
       //some calculations 
       select something).ToList(); 

// other calculations 

objects.ForEach(x => { 
    //some calculations 
    x.Property = "some text" 
}); 

return objects; 

Насколько я знаю, эти объекты не копируется, но ссылка ... не так ли? Что происходит за кодами видимости? В чем разница?

+0

Возможный дубликат [ToList() - Создать новый список?] (Http://stackoverflow.com/questions/2774099/tolist-does-it-create-a-new-list) –

+2

Когда вы do 'objects.ToList()' запрос выполняется. Затем вы возвращаете «объекты». Предположим, что кто-то затем перебирает этот возвращенный объект: в этом случае запрос будет выполнен снова (так будут созданы новые объекты) –

+5

'var objects' без' ToList' - это просто запрос, поэтому определение не выполняется. Если вы материализуете его, например, с помощью 'ToList' или' forach', он выполняется. Таким образом, добавляя «ToList», база данных запрашивается и заполняется список в памяти. 'List.ForEach' перечислит их, и вы измените свойство. В первом подходе этот список немедленно отбрасывается, поскольку он не сохраняется в переменной. Вторая версия верна. –

ответ

6

Помните, что запрос Linq это просто запрос. - он говорит «если я прошу этих данных, вот что я want_ Он не имеет каких-либо данных, но ждет, пока вы не ask_ результатов (через foreach, ToList, ToArray и т.д.)

разница в том, что вы не захвата список возвращенное ToList в первом примере. Она используется ForEach вызова, но переменная objects еще содержит ссылку на оригинальный запрос. Когда вы снова запрашиваете его, он снова извлекает данные. Когда он снова извлекает данные, создаются новые объекты.

В этом отношении - да ToList() создает новый список. Это не изменить объект, который он призвал превратить в список.

В вашем втором примере переменная objects содержит ссылку на список генерируется из запроса с помощью ToList(), поэтому при их изменении и возврата objects вы возвращаясь в тот же список.

+2

@Teemyr Я думаю, что вы тот, кто не понимает. То, что DSTanley и я написал в наших ответах, - это именно то, что происходит. – rinukkusu

+0

@Teemyr Я перечитал его. Благодарю. –

+0

@DStanley Первое редактирование делает значительное улучшение. Хотя я бы предпочел ответ, который делает его явным, что новые элементы создаются с помощью select. – Taemyr

0

В вашем первом примере кода objects.ToList() фактически создает новый объект типа List, над которым вы работаете с ForEach. После завершения ForEach вы все равно возвращаете свой IEnumerable, и список, который вы действительно хотели вернуть, исчезнет.

Задав запрос LINQ ToList() переменной object, вы используете только что созданный список в своем ForEach.

+0

Я думаю, вы пропустите пункт. Его изменения в объектах в списке отсутствуют. – Taemyr

+1

Именно потому, что он возвращает «IEnumerable» и не сохраняет результирующий список «ToList()» в своем первом примере. – rinukkusu

+1

@Taemyr Ключ к этому состоит в том, что 'IEnumerable', скорее всего, является« IQueryable », что означает, что базовые данные не являются объектами, которые можно изменить, а данные, которые будут запрашиваться из БД на каждой итерации. – juharr

Смежные вопросы