MemoryStream создает исключение ObjectDisposedException при попытке доступа к нему самостоятельно с помощью оператора using - PullRequest
0 голосов
/ 15 сентября 2018

Я пытаюсь использовать потоки, чтобы постепенно отображать JPEG при загрузке.Раньше это работало нормально, но сегодня утром я попытался запустить свой код, и теперь из-за этой ошибки невозможно загрузить изображения.Соответствующий код выглядит следующим образом:

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.

После использования Console.WriteLine в конце последнего оператора using (после цикла while) я обнаружил, что код, кажется, проходит циклпару раз, прежде чем выдать это исключение.

Я не понимаю, почему я буду пытаться получить доступ к закрытому потоку, когда код явно происходит внутри оператора using, что поток объявленв. Я также не понимаю, почему это сработало на днях и не сейчас.Большая часть кода для этого взята из здесь , поэтому остальную часть моего метода можно найти там.Мой не сильно отличается от некоторых изменений имен переменных и других небольших изменений.Кто-нибудь может помочь исправить это?

Редактировать: My _ProgressChanged event:

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
        }));
    }
}

1 Ответ

0 голосов
/ 15 сентября 2018

Как я и подозревал, это потому, что вы неправильно используете MemoryStream в вашем ProgressChanged обработчике.

Эта строка:

using (MemoryStream stream = e.UserState as MemoryStream)

принимает объект потока, который был переданна ProgressChanged() и будет позже в делегате Dispose этого.Но это точно такой же объект потока, который вам интересен, как он был расположен внутри вашего DoWork метода.

Этот поток не «принадлежит» обработчику ProgressChanged.Он не должен избавляться от него.

Это несколько тонко, но в связанном вопросе единственное, что делается с переданным потоком - это доступ к его методу ToArray.С этим также нужно быть осторожным, поскольку ProgressChangedDispatcher.BeginInvoke) асинхронный, вы можете легко иметь дело с уже расположенным объектом в этом обработчике (но ToArray безопасно вызывать на удаленном MemoryStream s)

Вы также можете рассмотреть извлечение массива byte[] из MemoryStream внутри вашего DoWork метода и сделать таким, чтобы передавалось состояние вместо MemoryStream.Это сделало бы его менее склонным к неправильному использованию как сейчас, так и при любых будущих изменениях этого кода.

...