При использовании лямбда-выражений или анонимных методов в С# мы должны опасаться доступа к модифицированной ловушке закрытия. Например:
foreach (var s in strings)
{
query = query.Where(i => i.Prop == s); // access to modified closure
...
}
Из-за модифицированного закрытия вышеупомянутый код приведет к тому, что все предложения Where
в запросе будут основаны на конечном значении s
.
Как объясняется здесь, это происходит потому, что переменная s
, объявленная в цикле foreach
выше, переводится как это в компиляторе:
string s;
while (enumerator.MoveNext())
{
s = enumerator.Current;
...
}
вместо этого:
while (enumerator.MoveNext())
{
string s;
s = enumerator.Current;
...
}
Как указано здесь, нет никаких преимуществ в производительности для объявления переменной за пределами цикла, и при нормальных обстоятельствах единственной причиной, по которой я могу это сделать, является если вы планируете использовать переменную вне рамки цикла:
string s;
while (enumerator.MoveNext())
{
s = enumerator.Current;
...
}
var finalString = s;
Однако переменные, определенные в цикле foreach
, не могут использоваться вне цикла:
foreach(string s in strings)
{
}
var finalString = s; // won't work: you're outside the scope.
Таким образом, компилятор объявляет переменную таким образом, что она сильно подвержена ошибкам, которые часто трудно найти и отладить, при этом не получая никаких ощутимых преимуществ.
Есть ли что-то, что вы можете сделать с foreach
, таким образом, что вы не могли бы, если бы они были скомпилированы с переменной с внутренней областью, или это просто произвольный выбор, который был сделан до анонимных методов и лямбда-выражений или общий, и который не был пересмотрен с тех пор?