为什么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构造函数上的boolean leaveOpen参数确保处理(关闭)它也不会关闭流

代码分析是对的; 代码分析是错误的。

是的,你正在关闭FileStream两次。 这是无害的。 所以要两次处理它。 多次处理发生。 一次性部件的开发者有责任正确处理多次处理而不抛出exception1

但是,虽然按照惯例调用已Dispose() FileStream上的Dispose()是一个无操作,但对于在已调配的流上调用Close()代码也是如此。 不要那样做。

您使用嵌套使用建议的修复很好。


1 IDisposable.Dispose的合同要求:

如果多次调用对象的Dispose方法,则该对象必须忽略第一个之后的所有调用。 如果多次调用Dispose方法,则该对象不得抛出exception。 除了Dispose之外的实例方法可以在已经ObjectDisposedException资源时抛出ObjectDisposedException

这种行为的正式术语是幂等性