空条件运算符和 CA2202:不要多次处理对象

Posted

技术标签:

【中文标题】空条件运算符和 CA2202:不要多次处理对象【英文标题】:null-conditional operator and CA2202: Do not dispose objects multiple times 【发布时间】:2016-04-10 08:59:55 【问题描述】:

具备以下条件:

StringWriter sw = null;
try

    sw = new StringWriter();
    using (var xw = new XmlTextWriter(sw))
    
        doc.WriteTo(xw);
        return sw.ToString();
    

finally 

    sw?.Dispose();

在 Visual Studio 2015 中触发 CA2202(不要多次释放对象)警告。

但如果将fianlly 块更改为:

finally 

    if (sw != null)
    
        sw.Dispose();
    

这是finally块中的空条件运算符的一些奇怪之处还是什么,或者Visual Studio中的分析工具根本不理解它?

编辑:可能相关:Why does Code Analysis flag me when using the null conditional operator with Dispose()?

【问题讨论】:

是否有任何理由执行手动处理,而不仅仅是使用using 语句? 其实警告是正确的。 StringWriter 被释放两次,因为XmlTextWriter.Dispose() 将释放它。 @Henrik:但这并不能解释为什么行为会发生变化。如果您不明确 Dispose,我希望会触发警告,因为 XmlTextWriter 的行为是其实现的附带行为。 我正在手动处理以避免StringWriter 被处理两次。如果XmlTextWriter 释放了StringWriter,那么null 条件应该确保它不会被再次释放。 如果您查看警告的解决方案:msdn.microsoft.com/library/ms182334.aspx 您会发现问题不在于代码结构,而只是我使用的是 null 条件而不是 @ 987654335@ 块。对吗? 【参考方案1】:

因为您在 using 块中声明了 xw,所以当您退出 using 块时,将调用 XmlTextWriter 的 IDisposable 方法。由于您的字符串编写器仅与 XMLWriter 一起使用,因此垃圾收集器也将处理它(这是一种优化,可以使 GC 不必依赖引用计数来确定对象是否仍在使用中)。

编辑: 更多信息可以在this MSDN 文章中找到。

【讨论】:

我认为您在这里混淆了处置和内存释放。如果您不这样做,GC 将不会在您的对象上调用 Dispose(如果有,它将调用终结器),并且它不会进行引用计数不管 - 它释放任何没有根的对象的内存(这基本上意味着:在运行代码的任何地方都没有对它的引用)。 问题不在代码中。正如我所说,如果我使用 MS 在此处提供的模式,则不会触发警告:msdn.microsoft.com/library/ms182334.aspx。问题是当我使用空条件运算符时会触发警告 - 好像 VS 中的代码分析不知道它做了什么。 我遇到了 VS 代码分析标记不应该出现的问题的问题。你可以只取消那段代码的警告。【参考方案2】:

警告“CA2202”是正确的。

如果'xw'被创建,'sw'应该在'xw'中被删除,或者如果'xw'失败则手动删除。

所以你需要在创建 'xw' 之后使用 'sw = null'。

StringWriter sw = null;
try

    sw = new StringWriter();
    using (var xw = new XmlTextWriter(sw))
    
        sw = null; //need to set null
        doc.WriteTo(xw);
        return sw.ToString();
    

finally

    sw?.Dispose();

【讨论】:

以上是关于空条件运算符和 CA2202:不要多次处理对象的主要内容,如果未能解决你的问题,请参考以下文章

警告:不要多次处理对象[重复]

在处置模式中使用空条件运算符时 CA2213 触发

您不应在一个对象上多次调用 Dispose(CA2202)[重复]

为啥嵌套的 using 块会多次处理对象? [复制]

Android实战开发篇 快速点击AlertDialog多次触发条件导致弹出多个Dialog

处理具有 2 个流的对象