2014-11-20 4 views
3

Resharper предлагает использовать верхний пример в нижнем примере. Однако у меня создается впечатление, что сначала будет создан новый список элементов, и, таким образом, все _executeFuncs будут запущены до вызова runstoredprocedure.Resharper, linq в цикле foreach

Это, как правило, не является проблемой, однако существуют исключения, и если моя гипотеза правильная, то моя база данных не будет обновляться, несмотря на то, что функции были запущены?

foreach (var result in rows.Select(row => _executeFunc(row))) 
    {     
     RunStoredProcedure(result) 
    } 

Или

foreach(var row in rows) 
    { 
     var result = _executeFunc(row); 
     RunStoredProcedure(result); 
    } 
+0

Вы имеете в виду исключения могут произойти в '_executeFunc'? – Alexandru

+0

Читайте об отложенном исполнении. –

+0

извиняется, да executeFunc (строка) подвержен ошибкам – McShep

ответ

4

Операторы в этом случае семантически такие же, как Select (и linq в целом) используют отложенное выполнение делегатов. Он не будет запускать объявленные запросы до тех пор, пока результат не будет реализован, и в зависимости от того, как вы напишете этот запрос, он будет делать это в правильной последовательности.

Очень простой пример, чтобы показать, что:

var list = new List<string>{"hello", "world", "example"}; 

Func<string, string> func = (s) => { 
    Console.WriteLine(s); 
    return s.ToUpper(); 
}; 

foreach(var item in list.Select(i => func(i))) 
{ 
    Console.WriteLine(item); 
} 

приводит

hello 
HELLO 
world 
WORLD 
example 
EXAMPLE 
4

В первом примере, _executeFunc(row) НЕ будет называться первым для каждого элемента в rows перед началом вашей foreach цикла. LINQ отложит выполнение. См. This answer для более подробной информации.

Порядок событий будет:

  1. Оценить первый элемент в rows
  2. Зов executeFunc(row) по этому пункту
  3. вызова RunStoredProcedure(result)
  4. Повторите со следующим пунктом в rows

Теперь, если ваш код был примерно таким:

foreach (var result in rows.Select(row => _executeFunc(row)).ToList()) 
{     
    RunStoredProcedure(result) 
} 

Затем он побежал бы LINQ .Select первым для каждого элемента в rows, поскольку .ToList() вызывает сбор переписываются.

+0

Спасибо, ребята, действительно хорошие ответы, хотелось бы, чтобы я мог выбрать оба как правильные ответы. Я выбрал J. Steen's, поскольку он предоставил выходной пример извините – McShep

+0

Без проблем, рад, что вы нашли свой ответ! –

2

Select использует отложенное выполнение. Это означает, что он будет в порядке:

  • взять элемент из rows
  • вызова _executeFunc на нем
  • вызов RunStoredProcedure на результат _executeFunc

И тогда он будет делать то же самое для следующего элемента, пока весь список не будет обработан.

3

В верхнем примере, используя Select, проецируют строки по yielding им по одному.

Так

foreach (var result in rows.Select(row => _executeFunc(row)))

в основном такая же, как

foreach(var row in rows)

Таким образом, Select делает что-то вроде этого

for each row in source 
    result = _executeFunc(row) 
    yield result 

Это выход проходящей каждую строку назад один одним (это немного сложнее, но этого объяснения пока достаточно).

Если вы сделали это вместо

foreach (var result in rows.Select(row => _executeFunc(row)).ToList())

Вызов ToList() возвращает список строк сразу, и это означает, что _executeFunc() действительно будет вызываться для каждой строки, прежде чем вы имели шанс позвоните по телефону RunStoredProcedure().

Таким образом, то, что предлагает Resharper, действительно. Чтобы быть справедливым, я уверен, что разработчики JetBrains знают, что они делают :)

1

Казнь будет отложено означает, что они будут иметь тот же Exec

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