我有以下代码循环遍历数组,其中数组元素存储文件名。每个循环,代码加载XML文档。当我直接调用数组元素时,我收到一个异常,说索引在数组的边界之外,但如果我将数组元素存储到一个单独的变量,代码编译就好了。
我只是无法理解为什么会有差异,为什么一个工作但不能另一个工作。
编译好
for(int i =0; i < MyArray.Count(); i++)
{
string myString = MyArray[i].Split(',')[0];
Dispatcher.BeginInvoke(new Action(() =>
{
string xmlPath = _PATH + + myString;
var document = XDocument.Load(xmlPath, LoadOptions.SetLineInfo);
}));
}
}
例外:索引超出了数组的边界
for(int i =0; i < MyArray.Count(); i++)
{
Dispatcher.BeginInvoke(new Action(() =>
{
string xmlPath = _PATH + + MyArray[i].Split(',')[0];
var document = XDocument.Load(xmlPath, LoadOptions.SetLineInfo);
}));
}
}
答案 0 :(得分:2)
问题是由“变量捕获”引起的,它使用i
的最终值而不是您调用它时的值。要解决这个问题,请在循环内部创建一个局部变量,然后使用它。
for(int i =0; i < MyArray.Count(); i++)
{
int j = i;
Dispatcher.BeginInvoke(new Action(() =>
{
string xmlPath = _PATH + + MyArray[j].Split(',')[0];
var document = XDocument.Load(xmlPath, LoadOptions.SetLineInfo);
}));
}
}
答案 1 :(得分:2)
基本上这是Captured变量的已知行为。它们是lambda表达式/语句使用的外部变量。这些类型的lambda表达式/语句称为Closures。众所周知,lambda表达式的延迟执行。在执行时,它们使用捕获变量的当前值而不是创建它们时的值。
为了解决这个关闭问题,有一种普遍的补救措施。每当我们需要在闭包中捕获变量时,我们必须通过在lambda中声明一个局部变量并将捕获变量的值赋给此局部变量来制作变量的局部副本。