在此代码中:
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的代码分析工具,我得到了警告,"不要多次处理对象……以避免生成系统。在"fStream.Close();"行中,你不应该在一个对象"上多次调用Dispose。
为什么?是否在上面的行中处理了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();
. . .
?
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));
}
这是防爆版本:
- 任何成功构建的东西都保证被处置
- 你不会释放流两次,因为
BinaryReader
构造函数上的布尔值leaveOpen
参数确保释放(关闭)它不会同时关闭流
代码分析正确;代码分析是错误的。
是的,您关闭了两次文件流。这是无害的。也就是处理两次。多重处置发生了。一次性组件的开发人员有责任正确地处理多个处置,并且不抛出异常1。
然而,虽然在已处置的FileStream
上调用Dispose()
按照惯例是无操作的,但在已处置的流上调用Close()
的代码并非如此。别那样做。
你建议的修复嵌套使用是好的。
1 IDisposable.Dispose
的合同要求:
如果一个对象的
Dispose
方法被调用了不止一次,该对象必须忽略第一次之后的所有调用。如果多次调用该对象的Dispose
方法,则该对象不能抛出异常。当资源已经被释放时,Dispose
以外的实例方法可以抛出ObjectDisposedException
。
这种行为的正式术语是幂等性。