为什么Code Analysis告诉我,“不要多次丢弃对象”:
在这段代码上:
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的代码分析工具,警告,“ 不要多次丢弃对象……为了避免生成System.ObjectDisposedException,你不应该在对象上多次调用Dispose ” fStream.Close();” 线。
为什么? 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
构造函数上的booleanleaveOpen
参数确保处理(关闭)它也不会关闭流
代码分析是对的; 代码分析是错误的。
是的,你正在关闭FileStream两次。 这是无害的。 所以要两次处理它。 多次处理发生。 一次性部件的开发者有责任正确处理多次处理而不抛出exception1 。
但是,虽然按照惯例调用已Dispose()
FileStream
上的Dispose()
是一个无操作,但对于在已调配的流上调用Close()
代码也是如此。 不要那样做。
您使用嵌套使用建议的修复很好。
1 IDisposable.Dispose
的合同要求:
如果多次调用对象的
Dispose
方法,则该对象必须忽略第一个之后的所有调用。 如果多次调用Dispose
方法,则该对象不得抛出exception。 除了Dispose
之外的实例方法可以在已经ObjectDisposedException
资源时抛出ObjectDisposedException
。
这种行为的正式术语是幂等性 。