Dispatcher.BeginInvoke 数组循环异常

Dispatcher.BeginInvoke exception in an array loop

我有以下循环遍历数组的代码,其中数组元素存储文件名。每个循环,代码加载一个 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);
            }));
    }
}

问题是由 "variable capture" 引起的,它使用 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);
            }));
    }
}

基本上这是捕获变量的已知行为。它们是 lambda 表达式/语句使用的外部变量。这些类型的 lambda 表达式/语句称为闭包。众所周知,lambda 表达式会延迟执行。在执行时,它们使用捕获变量的当前值而不是创建时的值。

要解决这个闭包的问题,​​有万能的良方。每当我们需要在闭包中捕获变量时,我们必须通过在 lambda 中声明局部变量并将捕获变量的值分配给该局部变量来制作该变量的本地副本。