Ошибка «Объект может быть удален более одного раза» - PullRequest
39 голосов
/ 21 октября 2010

Когда я запускаю анализ кода на следующем фрагменте кода, я получаю это сообщение:

Объект «поток» может быть размещен более одного раза в методе «upload.Page_Load (object, EventArgs)».Чтобы избежать создания System.ObjectDisposedException, вы не должны вызывать Dispose более одного раза для объекта.

using(var stream = File.Open(newFilename, FileMode.CreateNew))
using(var reader = new BinaryReader(file.InputStream))
using(var writer = new BinaryWriter(stream))
{
    var chunk = new byte[ChunkSize];
    Int32 count;
    while((count = reader.Read(chunk, 0, ChunkSize)) > 0)
    {
        writer.Write(chunk, 0, count);
    }
}

Я не понимаю, почему он может быть вызван дважды, и как исправить это, чтобы устранить ошибку,Любая помощь?

Ответы [ 5 ]

20 голосов
/ 29 сентября 2012

Я боролся с этой проблемой и нашел пример здесь очень полезным.Я опубликую код для быстрого просмотра:

using (Stream stream = new FileStream("file.txt", FileMode.OpenOrCreate))
{
    using (StreamWriter writer = new StreamWriter(stream))
    {
        // Use the writer object...
    }
}

Замените внешний оператор using попыткой / наконец, убедившись, что ОБА обнулить поток после его использования в StreamWriter И проверить, чтобы убедиться, что это не такnull в finally перед удалением.

Stream stream = null;
try
{
    stream = new FileStream("file.txt", FileMode.OpenOrCreate);
    using (StreamWriter writer = new StreamWriter(stream))
    {
        stream = null;
        // Use the writer object...
    }
}
finally
{
    if(stream != null)
        stream.Dispose();
}

Это помогло исправить мои ошибки.

13 голосов
/ 21 октября 2010

Для иллюстрации давайте отредактируем ваш код

using(var stream = File.Open(newFilename, FileMode.CreateNew))
{
    using(var reader = new BinaryReader(file.InputStream))
    {
        using(var writer = new BinaryWriter(stream))
        {
            var chunk = new byte[ChunkSize];
            Int32 count;
            while((count = reader.Read(chunk, 0, ChunkSize)) > 0)
            {
                writer.Write(chunk, 0, count);
            }
        } // here we dispose of writer, which disposes of stream
    } // here we dispose of reader
} // here we dispose a stream, which was already disposed of by writer

Чтобы избежать этого, просто создайте писателя напрямую

using(var reader = new BinaryReader(file.InputStream))
    {
        using(var writer = new BinaryWriter( File.Open(newFilename, FileMode.CreateNew)))
        {
            var chunk = new byte[ChunkSize];
            Int32 count;
            while((count = reader.Read(chunk, 0, ChunkSize)) > 0)
            {
                writer.Write(chunk, 0, count);
            }
        } // here we dispose of writer, which disposes of its inner stream
    } // here we dispose of reader

edit: чтобы принять во внимание то, что говорит Эрик Липперт, действительно может быть момент, когда поток освобождается финализатором, только если BinaryWriter выдает исключение. Согласно коду BinaryWriter, это может произойти в трех случаях

  If (output Is Nothing) Then
        Throw New ArgumentNullException("output")
    End If
    If (encoding Is Nothing) Then
        Throw New ArgumentNullException("encoding")
    End If
    If Not output.CanWrite Then
        Throw New ArgumentException(Environment.GetResourceString("Argument_StreamNotWritable"))
    End If
  • если вы не указали вывод, т.е. если поток равен нулю. Это не должно быть проблемой, поскольку нулевой поток означает отсутствие ресурсов для удаления:)
  • если вы не указали кодировку. поскольку мы не используем форму конструктора, в которой указана кодировка, здесь также не должно возникнуть проблем (я не слишком много смотрел на конструктор кодирования, но может выдать недопустимую кодовую страницу)
    • если вы не передаете записываемый поток. Это должно быть поймано довольно быстро во время разработки ...

В любом случае, хорошая мысль, отсюда и правка:)

8 голосов
/ 21 октября 2010

BinaryReader / BinaryWriter будет располагать базовым потоком для вас при его удалении.Вам не нужно делать это явно.

Чтобы исправить это, вы можете удалить использование вокруг самого Stream.

5 голосов
/ 28 февраля 2011

Правильная реализация Dispose явно требуется, чтобы не заботиться о том, был ли он вызван более одного раза для одного и того же объекта.Хотя множественные вызовы Dispose иногда указывают на логические проблемы или код, который можно было бы лучше написать, единственный способ улучшить исходный опубликованный код - убедить Microsoft добавить опцию в BinaryReader и BinaryWriter, инструктируя их не удалять свои переданныев потоке (и затем используйте эту опцию).В противном случае код, необходимый для обеспечения того, чтобы файл закрывался, даже если читатель или писатель добавляет его конструктор, был бы достаточно уродливым, чтобы простое удаление файла более одного раза показалось бы более чистым.

5 голосов
/ 21 октября 2010

Ваш писатель будет распоряжаться вашим потоком всегда.

...