来自封闭块的变量在匿名函数中变为空

Variable from enclosing block becomes null in anonymous function

var client = new WebClient();
var bytes = client.DownloadData(webUrl); // <-- NOT null

Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
    BitmapImage img = new BitmapImage();
    img.BeginInit();
    img.StreamSource = new MemoryStream(bytes); // <-- null
    img.EndInit();
    img_DownloadCompleted(img, webUrl);
}));

bytes = null; // EDIT: This last line is what I did wrong. This line
              // of code is executed in PARALLEL with the anonymous 
              // function, and thus this variable is set to null
              // sometime while (or before) the lambda is executing.

以上代码在一个线程中执行以避免阻塞UI。

我正在尝试从 Internet 下载图像到 BitmapImage 对象中。图片已正确下载,但当我尝试在我的 UI 中使用它时(使用 Dispatcher.Invoke),我收到此错误消息:The calling thread cannot access this object because a different thread owns it.

所以我添加了在 UI 线程上创建图像的代码。但是现在,当代码到达 <-- null 指示的行时,变量 bytes 突然变为空。在执行进入匿名函数之前它不是空的。 (我用调试器检查过)

有人知道这是为什么吗? Google 不是很有帮助。

bytes 的变量类型更改为 var 没有任何区别。

很可能您稍后要更改 bytes 变量,因此会修改匿名函数内的 "captured" 值。类似于:

var bytes = client.DownloadData(webUrl); <-- NOT null
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
 ...  img.StreamSource = new MemoryStream(bytes); <-- null
 ...
}
bytes = null; // something like this - because why not? 

请注意,即使代码看起来像顺序的并且 img.StreamSource = ...before bytes = null; 行,它实际上可能会以相反的顺序执行(不确定它在其他线程上运行)。

您应该非常小心这种将异步执行的捕获 later/on 其他线程。更安全的选择是在单独的方法中创建匿名函数,这样您以后就无法更改捕获的变量:

Action CreateBitmapAction(bytes[] bytes)
{
 return () =>
 {
    BitmapImage img = new BitmapImage();
    img.BeginInit();
    img.StreamSource = new MemoryStream(bytes);
    img.EndInit();
    img_DownloadCompleted(img, webUrl);
 };
}

Application.Current.Dispatcher.BeginInvoke(CreateBitmapAction(bytes));

这是由为方法创建的闭包引起的。 它引用了一个超出其范围的对象。 Alexei 的回答将解决问题。

但是如果您仍然不想在代码中保留类似 lambda 的语法,您可以像这样做同样的事情:

   var bytes = client.DownloadData(webUrl);
   Application.Current.Dispatcher.BeginInvoke((Action<byte[]>)(b => 
   {
       // draw a pink bunny , or what ever here.   
   }),bytes);