【问题标题】:Should I heed this superficially nonsensical Code Analysis warning? [duplicate]我应该注意这个表面上无意义的代码分析警告吗? [复制]
【发布时间】:2016-05-26 17:53:42
【问题描述】:

当我在 Visual Studio 2013 中选择“分析”>“对解决方案运行代码分析”时,我得到,“CA2202 不要多次处理对象对象 'fs' 可以在方法 'RoboReporterSQL.SaveReportDataToDB(string , string)'。为避免生成 System.ObjectDisposedException,您不应在一个对象上多次调用 Dispose。"

指示的代码行是:

fs.Close();

这是上下文中的代码:

    internal static void SaveReportDataToDB(string filename, string 
RESTFilename)
    {
        if (RecordAlreadyExists(RESTFilename)) return;
        string EXCEL_FILE = "application/vnd.ms-excel";
        DateTime begDate = 
RoboReporterConstsAndUtils.GetBeginDate(RESTFilename);
        DateTime endDate = 
RoboReporterConstsAndUtils.GetEndDate(RESTFilename);

        var fs = new FileStream(filename, FileMode.Open, FileAccess.Read);
        BinaryReader br = new BinaryReader(fs);
        Byte[] bytes = br.ReadBytes((Int32)fs.Length);
        br.Close();
        fs.Close();

        using (var sqlConn = new SqlConnection(CPSConnStr))
        {
            var insertStr = "INSERT INTO ReportsGenerated (FileBaseName, 
ContentType, BinaryData, BeginDate, EndDate) " +
                             "VALUES (@FileBaseName, @ContentType, 
@BinaryData, @BeginDate, @EndDate)";

            using (var insertRptsGenerated = new SqlCommand(insertStr))
            {
                insertRptsGenerated.Connection = sqlConn;
                insertRptsGenerated.Parameters.Add("@FileBaseName", 
SqlDbType.VarChar, 100).Value = RESTFilename;
                insertRptsGenerated.Parameters.Add("@ContentType", 
SqlDbType.VarChar, 50).Value = EXCEL_FILE;
                insertRptsGenerated.Parameters.Add("@BinaryData", 
SqlDbType.Binary).Value = bytes;
                insertRptsGenerated.Parameters.Add("@BeginDate", 
SqlDbType.DateTime).Value = begDate;
                insertRptsGenerated.Parameters.Add("@EndDate", 
SqlDbType.DateTime).Value = endDate;
                sqlConn.Open();
                insertRptsGenerated.ExecuteNonQuery();
            }
        }
    }

所以警告声称如果我调用“fs.Close();”,FileStream 将被关闭两次

虽然我不能肯定地反驳这一点,但我会质疑它,因为我没有看到它在其他地方关闭。

毕竟不是在“使用”块中,怎么关闭呢?

问题是:我真的应该删除那行代码(“fs.Close();”)吗?

注意:Resharper 并没有对此一无所知 - 使用“fs.Close();”无论进出,它都不会引发任何警告标志。

【问题讨论】:

  • 您将其关闭两次。您在关闭 BinaryReader 时将其关闭 - 它还会关闭底层流。你真的应该使用
  • 这在 SO 上被讨论死了,只有你的声誉才能让这个问题保持活力......
  • 我想知道在这种情况下错误的措辞是否刚刚结束。如果关闭BinaryReader 可能会导致FileStream 被释放,那么访问已释放对象的Close 方法可能会抛出ObjectDisposedException。

标签: c# filestream dispose objectdisposedexception


【解决方案1】:

坦率地说,您不应该明确关闭这些流,您应该使用 using 块。

无论如何,它会给你这个警告,因为流已经关闭。当读取器/写入器包装流时,关闭它们也会关闭底层流。但是,一些读者/作者会为您提供让流保持打开状态的选项。

在您的特定情况下,您可以使用 File 类中提供的其他一些方法,用一块石头杀死两只鸟。考虑使用File.ReadAllBytes() 读取您的文件。

【讨论】:

    【解决方案2】:

    想补充一点,它仍然是非常无用的警告。我从未见过IDisposable 的任何实现,当您多次调用 Dispose 时会抛出ObjectDisposedException。实际上在IDisposable.Dispose的文档中写了以下内容:

    如果多次调用对象的 Dispose 方法,则对象必须忽略第一次调用之后的所有调用。如果多次调用对象的 Dispose 方法,则该对象不得抛出异常

    但是,您在流上调用 Close,而不是 Dispose,虽然在这种情况下它是相同的,但通常您确实不应该在已处理的对象上调用任何非 Dispose 方法,因此至少将 Close 更改为 Dispose(或更好全部使用)。

    【讨论】:

    • 我想知道它是否会认为因为 BinaryReader 已关闭,FileStream 可能会被处置。因此,警告表明访问已处置的FileStream (fs) 对象可能会导致ObjectDisposedMethod。我的意思是,如果你处理 FileStream 然后调用它的 Close 方法会发生什么?
    • 什么也没发生。但是如果你尝试做任何其他事情(读\写等)——那么它会抛出 ObjectDisposedException。我使用这种模式(将阅读器和流放在两个 using 块中)已经很多年了,没有任何麻烦。
    • 我不是指两次处理。我的意思是访问已经释放的对象的“关闭”方法可能会抛出不是吗?
    • Close 方法只是调用 Dispose,仅此而已。所以这些方法在它们的作用方面是相同的(所以你可以在任何时候调用它们,它们不会抛出 ObjectDisposed)。实际上对这条规则的描述(msdn.microsoft.com/en-us/library/ms182334.aspx)说不要多次处理,因为我在上面的回答中所说的“将来可能会改变”。我怀疑这种情况会改变,因为没有理由在多个 dispose 调用上抛出异常。
    • 再想一想,我认为即使在这种情况下它是无害的 - 你确实不应该在已处理的流上调用 Close。它调用 Dispose 的事实是您不应该依赖的实现细节。您可以多次处理,但不能保证关闭。错过了,因为我从不在流上使用 Close 方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-02
    • 1970-01-01
    • 1970-01-01
    • 2016-08-08
    • 2021-12-03
    • 1970-01-01
    相关资源
    最近更新 更多