Каково точно Внешнее Переменное Прерывание? Объяснение и примеры в C# ценятся.
Править: Слияние диктата Jon Skeet :)
"Ловушка внешней переменной" возникает, когда разработчик ожидает, что значение переменной будет захвачено лямбда-выражением или анонимным делегатом, когда на самом деле переменная захватывается сама.
Пример:
var actions = new List<Action>();
for (var i = 0; i < 10; i++)
{
actions.Add(() => Console.Write("{0} ", i));
}
foreach (var action in actions)
{
action();
}
Возможный вывод #1:
0 1 2 3 4 5 6 7 8 9
Возможный вывод #2:
10 10 10 10 10 10 10 10 10 10
Если вы ожидали вывод #1, вы попали в ловушку внешней переменной. Вы получите вывод №2.
Исправление:
Объявите "Внутреннюю переменную" для многократного захвата вместо "Внешней переменной", которая захватывается только один раз.
var actions = new List<Action>();
for (var i = 0; i < 10; i++)
{
var j = i;
actions.Add(() => Console.Write("{0} ", j));
}
foreach (var action in actions)
{
action();
}
Более подробно см. также блог Эрика Липперта.
Что-то вроде
foreach (var s in strings)
var x = results.Where(r => (r.Text).Contains(s));
не даст ожидаемых результатов, потому что Contains не выполняется для каждой итерации. Однако присвоение s временной переменной внутри цикла исправит это.
@dtb правильный (большой +1), но важно отметить, что это применимо, только если область закрытия выходит за пределы петли. Например:
var objects = new []
{
new { Name = "Bill", Id = 1 },
new { Name = "Bob", Id = 5 },
new { Name = "David", Id = 9 }
};
for (var i = 0; i < 10; i++)
{
var match = objects.SingleOrDefault(x => x.Id == i);
if (match != null)
{
Console.WriteLine("i: {0} match: {1}", i, match.Name);
}
}
Будет напечатано:
i: 1 match: Bill i: 5 match: Bob i: 9 match: David
ReSharper предупредит о «Доступе к измененному закрытию», которое в этом случае можно игнорировать.
Эта статья, объясняющая концепцию замыканий, полезна:
http://en.wikipedia.org/wiki/Closure_(computer_science)
Также эта статья очень хороша с более конкретной реализации C#:
http://blogs. msdn.com/b/abhinaba/archive/2005/08/08/448939.aspx
В любом случае, суть в том, что область видимости переменных так же важна в анонимных делегатах или лямбда-выражениях, как и в любом другом месте вашего кода - поведение просто не так очевидно.