Почему анализ кода говорит мне:" не размещайте объекты несколько раз " здесь:
По этому коду:
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 ответа:
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()
на disposedFileStream
является no-op по соглашению, то же самое не верно для вашего кода, который вызываетClose()
на disposed stream. Не делай этого.Предложенное вами исправление с вложенным использованием прекрасно.
1контракт для
IDisposable.Dispose
требуется:Если метод объекта
Dispose
вызывается более одного раза, объект должен игнорировать все вызовы после первого. Объект не должен вызывать исключение, если его методDispose
вызывается несколько раз. Методы экземпляра, отличные отDispose
, могут выбрасыватьObjectDisposedException
, когда ресурсы уже расположены.Формальный термин для этого поведение idempotence.