为什么代码分析告诉我“不要多次处理对象”?:在这里

本文关键字:对象 处理 在这里 代码 告诉我 为什么 | 更新日期: 2023-09-27 18:09:32

在此代码中:

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

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