MemoryStream 尝试在其自己的 using 语句中访问它时抛出 ObjectDisposedException

MemoryStream throws ObjectDisposedException when trying to access it in its own using statement

我正在尝试使用流在加载时逐步显示 jpeg。这曾经工作正常,但今天早上我尝试 运行ning 我的代码,现在由于这个错误无法加载图像。相关代码如下:

using (WebClient wc = new WebClient())
using (Stream streamRemote = wc.OpenRead(url))
using (Stream streamLocal = new MemoryStream((int)fileSize))
{
    int byteSize = 0;
    byte[] buffer = new byte[fileSize];

    while ((byteSize = streamRemote.Read(buffer, 0, buffer.Length)) > 0)
    {
        streamLocal.Write(buffer, 0, byteSize); // Error is here.
        bytesDownloaded += byteSize;

        int progressPercentage = (int)(bytesDownloaded / buffer.Length) * 100;

        if (progressPercentage % 10 == 0)
        {
            imageLoader.ReportProgress(progressPercentage, streamLocal);
        }
    }
}

// Exception thrown: 'System.ObjectDisposedException' in mscorlib.dll
// An exception of type 'System.ObjectDisposedException' occurred in mscorlib.dll but was not handled in user code
// Cannot access a closed Stream.

在最终 using 语句的末尾使用 Console.WriteLine 之后(在 while 循环之后),我发现代码似乎 运行 在抛出之前循环了几次那个例外。

我不明白为什么我会在代码明显发生时尝试访问已关闭的流声明流的 using 语句中。我也不不明白为什么它前几天有效而现在无效。大部分代码来自 here,所以我的方法的其余部分可以在那里找到。除了一些变量名更改和其他小的更改外,我的并没有太大的不同。谁能帮忙解决这个问题?

编辑:我的 _ProgressChanged 事件:

private void ImageLoader_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    if (!fileFailed)
    {
        Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal,
        new Action(delegate ()
        {
            try
            {
                using (MemoryStream stream = e.UserState as MemoryStream)
                {
                    BitmapImage bmp = new BitmapImage();
                    bmp.BeginInit();
                    using (MemoryStream ms = new MemoryStream(stream.ToArray())) bmp.StreamSource = ms;
                    bmp.EndInit();

                    img_CurrentImage.Source = bmp;
                }
            }
            // A few catch statements here - none of the exceptions here are being thrown anyway so I'll omit the catch statements
        }));
    }
}

正如我所怀疑的,这是因为您在 ProgressChanged 处理程序中滥用了 MemoryStream

这一行:

using (MemoryStream stream = e.UserState as MemoryStream)

正在获取传递给 ProgressChanged() 的流对象,稍后将在它的委托 Dispose 中。但那是完全相同的流对象,你想知道它是如何在你的DoWork方法中处理的。

该流不会 "belong" 到 ProgressChanged 处理程序。它不应该处理它。

这有点微妙,但在链接的问题中,对传入流所做的唯一事情就是访问它的 ToArray 方法。你也需要小心做,因为 ProgressChanged (和 Dispatcher.BeginInvoke)是异步的,你可以很容易地处理这个处理程序中已经处理的对象(但是 ToArray 是安全的呼吁处置 MemoryStreams)

您还可以考虑从 DoWork 方法中的 MemoryStream 中提取 byte[] 数组,并使 that 成为传递状态而不是MemoryStream。这将大大降低现在和将来对此代码的任何编辑中的误用。