Почему анализ кода говорит мне:" не размещайте объекты несколько раз " здесь:


По этому коду:

public static string Base64FromFileName(string fileName)
{
    try
    {
        FileInfo fInfo = new FileInfo(fileName);
        long numBytes = fInfo.Length;
        FileStream fStream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
        BinaryReader br = new BinaryReader(fStream);
        byte[] bdata = br.ReadBytes((int)numBytes);
        br.Close();
        fStream.Close();
        return Convert.ToBase64String(bdata);
    }
    catch(Exception e)
    {
        throw e;
    }
}

...Я получаю, благодаря инструменту анализа кода Visual Studio, предупреждение: "Не размещайте объекты многократно times...To избегайте создания системы.ObjectDisposedException не следует вызывать Dispose более одного раза для объекта " на " fStream.Замкнутая линия.

Почему? Расположен ли fStream в строке выше, где BinaryReader закрыт?

Не лучше ли мне все равно рефакторинговать его так:

. . .
using (FileStream fStream = new FileStream(fileName, FileMode.Open, FileAccess.Read))   
{
    using (BinaryReader br = new BinaryReader(fStream)) 
    {
        byte[] bdata = br.ReadBytes((int)numBytes);
    } //br.Close();
} //fStream.Close();
. . .

?

2 2

2 ответа:

BinaryReader.Close Кроме того, закрывает основной поток, так что это действительно приведет к тому, что поток будет удален дважды. Но это не настоящая проблема, избавиться дважды не повредит.

Вы могли бы написать это гораздо лучше, как

using (var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read))
using (var br = new BinaryReader(fs, new UTF8Encoding(), true))
{
    return Convert.ToBase64String(br.ReadBytes((int)numBytes));
}

Это бомбоубежищная версия:

  • Все, что успешно построено, гарантированно будет утилизировано
  • вы не будете избавляться от потока дважды, потому что логический аргумент leaveOpen в конструкторе BinaryReader гарантирует, что утилизации (закрытии) его не закрыть поток

Анализ кода-это правильно; анализ кода-это неправильно.

Да, вы закрываете поток файлов дважды. Это безобидно. Так же как и избавление от него дважды. Происходит многократная утилизация. Ответственность разработчика одноразового компонента заключается в том, чтобы правильно и без исключений обрабатывать многократную утилизацию.1.

Однако, в то время как вызов Dispose() на disposed FileStream является no-op по соглашению, то же самое не верно для вашего кода, который вызывает Close() на disposed stream. Не делай этого.

Предложенное вами исправление с вложенным использованием прекрасно.


1контракт для IDisposable.Dispose требуется:

Если метод объекта Dispose вызывается более одного раза, объект должен игнорировать все вызовы после первого. Объект не должен вызывать исключение, если его метод Dispose вызывается несколько раз. Методы экземпляра, отличные от Dispose , могут выбрасывать ObjectDisposedException, когда ресурсы уже расположены.

Формальный термин для этого поведение idempotence.