Вот как это может укусить вас.Пример немного надуман, но вы поймете идею.
public static void SynchCreativesForCampaign(int pid, ILogger logger)
{
var db = new SynchDbDataContext(true);
CreativeEntity creativeEntity = null; // NEW: pull this out of the loop
foreach (var creativeItem in CreativeList.Create(pid).CreativeItems)
{
logger.Log(@"creative id " + creativeItem.CreativeId);
var creativeDetail = CreativeDetail.Create(creativeItem.CreativeId);
if (creativeEntity != null) {
continue; // NEW: let the loop go on, but make sure we only
// wrote to creativeEntity *once*
}
// IMPORTANT: notice I don't immediately call FirstOrDefault!
creativeEntity = from c in db.CreativeEntities
where c.dtid == creativeItem.CreativeId
select c;
}
if (creativeEntity != null)
{
// Only NOW evaluate the query
var result = creativeEntity.FirstOrDefault();
// OK, stop: result holds the creative entity with the dtid
// referring to which CreativeItem.CreativeId?
}
}
Вы можете ответить «с помощью dtid, ссылающегося на первый элемент в коллекции CreativeItems, который мы перебрали», но реальность такова, чтоон будет ссылаться на последний один (по этой причине я позволил циклу continue
- он ничего не сделал , кроме изменения значения creativeItem
, которое было необходимо дляпусть всплывет ошибка).
Код работает, выполняя некоторый компилятор voodoo, который по сути продлевает время жизни переменной creativeItem
до точки, где вы оцениваете запрос .Таким образом, хотя это выглядит так, что после foreach
end creativeItem
больше не существует, на самом деле он ждет где-то в памяти и, конечно, его значение остается неизменным по сравнению с тем, что было во время последней итерации.
Теперьрассмотрим, что произойдет, если вы скопируете значение creativeItem
в другую переменную с областью действия только внутри цикла foreach
.Теперь продлен срок жизни переменной, но есть важное отличие: эта переменная, находящаяся в области внутри foreach
, не будет повторно использоваться для нескольких итераций.В каждой итерации будет использоваться переменная new (с тем же именем, конечно), и это будет то значение, которое вы увидите при оценке запроса.