[英]MemoryStream throws ObjectDisposedException when trying to access it in its own using statement
I'm trying to use streams to progressively display a jpeg as it loads. 我正在尝试使用流在加载时逐步显示jpeg。 This used to work fine, but this morning I tried running my code and now no images can be loaded because of this error.
这曾经可以正常工作,但是今天早上我尝试运行我的代码,由于这个错误,现在无法加载任何图像。 The relevant code is as follows:
相关代码如下:
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.
After using Console.WriteLine at the end of the that final using statement (after the while loop), I've found that the code seems to run through the loop a couple times before throwing that exception. 在最后一个using语句的末尾(在while循环之后)使用Console.WriteLine之后,我发现该代码似乎在抛出该异常之前在循环中运行了两次。
I don't understand why I would be trying to access a closed stream when the code is clearly happening within the using statement that the stream is declared in. I also don't understand why it worked the other day and doesn't now. 我不明白为什么代码在声明了该流的using语句中明显发生时为什么要尝试访问封闭的流。我也不明白为什么它在前一天起作用了,但现在不起作用。 Most of the code for this comes from here , so the rest of my method can be found there.
大部分代码都来自这里 ,因此我的方法的其余部分可以在这里找到。 Mine isn't much different apart from some variable name changes and other small changes.
除了一些变量名更改和其他一些小的更改外,我的没有什么不同。 Can anyone help fix this?
谁能帮忙解决此问题?
Edit: My _ProgressChanged event: 编辑:我的_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
}));
}
}
As I suspected, it's because you're misusing the MemoryStream
in your ProgressChanged
handler. 正如我所怀疑的,这是因为您在
ProgressChanged
处理程序中滥用了MemoryStream
。
This line: 这行:
using (MemoryStream stream = e.UserState as MemoryStream)
Is taking the stream object that was passed to ProgressChanged()
and will later on in the delegate Dispose
of it. 正在获取传递给
ProgressChanged()
的流对象,稍后将在委托中对其进行Dispose
。 But that's exactly the same stream object that you're wondering how it got disposed inside your DoWork
method. 但这与您想知道如何将其放置在
DoWork
方法中的流对象相同 。
That stream doesn't "belong" to the ProgressChanged
handler. 该流不“属于”
ProgressChanged
处理程序。 It shouldn't be disposing of it. 它不应该处理它。
It's somewhat subtle, but in the linked question, the only thing that's done with the passed in stream is to access its ToArray
method. 这有些微妙,但是在链接的问题中,传入流唯一要做的就是访问其
ToArray
方法。 Which you need to also be careful to do since, because ProgressChanged
(and Dispatcher.BeginInvoke
) is asynchronous, you could easily be dealing with an already disposed object in this handler (but ToArray
is safe to call on disposed MemoryStream
s) 您还需要注意这一点,因为
ProgressChanged
(和Dispatcher.BeginInvoke
)是异步的,因此您可以轻松地在此处理程序中处理已经处置的对象(但是ToArray
可以安全地调用处置的MemoryStream
)
You might also consider extracting the byte[]
array from the MemoryStream
inside your DoWork
method and making that the passed state instead of the MemoryStream
. 您还可以考虑从
DoWork
方法内部的MemoryStream
提取byte[]
数组,并使该状态成为通过状态,而不是MemoryStream
。 That would make it far less prone to misuse both now and in any future edits to this code. 这样一来,现在以及以后对该代码进行的任何修改都将更不容易被滥用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.