嵌套 using 语句和 Microsoft 代码分析

发布于 2024-12-15 04:01:56 字数 1915 浏览 3 评论 0原文

最近我开启了额外的代码分析规则。 令我惊讶的是,我在我一直认为是最佳实践的地方看到了违规行为。 如果我有两个嵌套的一次性用品,我会放置两个像这样的 using 语句:

    using (StringReader strReader = new StringReader(xmlString))
    using (XmlReader xmlReader = XmlReader.Create(strReader))
    {
        result.ReadXml(xmlReader);
    }

这也对应于高评价的问答 C# 中的嵌套 using 语句

我得到的违规情况如下:

Warning 18  CA2202 : Microsoft.Usage : Object 'strReader' can be disposed more
than once in method '????'. To avoid generating a System.ObjectDisposedException
you should not call Dispose more than one time on an object.: Lines: ??

我所做的是一种直观的尝试和错误,认为外部流的关闭也可能会处理内部流,我快速修复了我的代码,如下所示:

    using (XmlReader xmlReader = XmlReader.Create(new StringReader(xmlString)))
    {
        result.ReadXml(xmlReader);
    }

Hura!警告消失了。但是,田田!新的情况发生了:

Warning 18  CA2000 : Microsoft.Reliability : In method '????????', object 
'new StringReader(xmlString)' is not disposed along all exception paths. Call
System.IDisposable.Dispose on object 'new StringReader(xmlString)' before all 
references to it are out of scope.

然后我发现了一个非常丑陋的解决方案:

    {
        StringReader strReader = null;
        try
        {
            strReader = new StringReader(xmlString);
            using (XmlReader xmlReader = XmlReader.Create(strReader))
            {
                strReader = null;
                result.ReadXml(xmlReader);
            }
        }
        finally
        {
            if (strReader != null) strReader.Dispose();
        }
    }

作为最后一步(就像每个优秀的程序员一样),我查看了 CA2202 的帮助页面,令我惊讶的是,我最后一个丑陋的解决方案正是被提出来解决这个问题的?

使用 try{} finally 会使代码变得非常混乱!对我来说,嵌套使用更具可读性。

问题:有更好的做事方式吗?我正在寻找一种可以直观理解的解决方案。每个看到最后一个片段的人都会对正在发生的事情感到好奇。

预先感谢您的回答。

Recently I switched on additional code analyses rules.
To my surprise I saw a violation in a place I was always considering as the best practice.
If I have two nested disposables I am putting two using statements like this:

    using (StringReader strReader = new StringReader(xmlString))
    using (XmlReader xmlReader = XmlReader.Create(strReader))
    {
        result.ReadXml(xmlReader);
    }

This also corresponds to the high rated Q&A
Nested using statements in C#

The violation I get states following:

Warning 18  CA2202 : Microsoft.Usage : Object 'strReader' can be disposed more
than once in method '????'. To avoid generating a System.ObjectDisposedException
you should not call Dispose more than one time on an object.: Lines: ??

What I did was an intuitive try and error, thinking that close of outer stream will also probably dispose the inner one I quick fixed my code like this:

    using (XmlReader xmlReader = XmlReader.Create(new StringReader(xmlString)))
    {
        result.ReadXml(xmlReader);
    }

Hura! The warning is gone. But, tada! The new one occurred:

Warning 18  CA2000 : Microsoft.Reliability : In method '????????', object 
'new StringReader(xmlString)' is not disposed along all exception paths. Call
System.IDisposable.Dispose on object 'new StringReader(xmlString)' before all 
references to it are out of scope.

Then I found a very ugly solution:

    {
        StringReader strReader = null;
        try
        {
            strReader = new StringReader(xmlString);
            using (XmlReader xmlReader = XmlReader.Create(strReader))
            {
                strReader = null;
                result.ReadXml(xmlReader);
            }
        }
        finally
        {
            if (strReader != null) strReader.Dispose();
        }
    }

As a very last step (like every good programmer) I looked into help page for CA2202 and to my surprise exactly my last UGLY solution was proposed to fix the issue?

Having try{} finally around using clutters the code very much! For me is the nested using much more readable.

Question: Is there a better way of doing things? I am looking for a solution which will be intuitively understandable. Everyone who will see this last snippet will be curios about what is happening.

Thanks in advance for your answers.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

猛虎独行 2024-12-22 04:01:57

问题不是因为嵌套使用。它们很好并且普遍推荐。这里的问题是,如果您传递带有 CloseInput == trueXmlReaderSettingsXmlReader 将处置 TextReader,但是CA2202 规则不够智能,您的代码不会进入该分支。保留嵌套使用,并将 CA2202 违规抑制为误报。

如果您希望在代码中明确显示以增强其可读性和/或可维护性,请使用 XmlReaderSettings,并将 CloseInput 设置为 false,但这是默认值,因此并不是绝对必要的,并且需要明确的是,它不会满足规则。

顺便说一句,对于各种流和读取器类型,都有类似的 CA2202 问题场景。不幸的是,它们与此并不完全相同,因此最佳案例处理可能会有所不同,具体取决于导致问题的类型。

The problem isn't because of the nested usings. They're fine and generally recommended. The problem here is that XmlReader will dispose the TextReader if you pass an XmlReaderSettings with CloseInput == true, but the CA2202 rule isn't smart enough that your code won't go down that branch. Keep your nested usings, and suppress the CA2202 violation as a false positive.

If you want to be explicit in your code in order to enhance its readability and/or maintainability, use an XmlReaderSettings with CloseInput set to false, but that is the default value, so it's not strictly necessary, and, to be clear, would not satisfy the rule.

BTW, there are similar CA2202 problem scenarios for a variety of stream and reader types. Unfortunately, they're not all the same as this one, so the best case handling can differ depending on which type is cause the problem.

世态炎凉 2024-12-22 04:01:57

我最近遇到了类似的问题,但由于我使用的是序列化器,所以必须对其进行调整,因为我无法立即将 stringWriter 设置为 null。此解决方法可避免所有 CA 警告:

StringWriter stringWriter = null;
XmlWriter xmlWriter = null;
string serializedValue = null;

try
{
    XmlSerializer xmlserializer = new XmlSerializer(typeof(T));
    stringWriter = new StringWriter();

    xmlWriter = XmlWriter.Create(stringWriter);
    xmlserializer.Serialize(xmlWriter, value);
    xmlWriter.Flush();
    serializedValue = stringWriter.ToString();
}
finally
{
    if (xmlWriter != null) //Both objects need disposed 
    {
        xmlWriter.Dispose(); //stringWriter will dispose automatically too
    }
    else if (stringWriter != null) //XmlWriter failed to create
    {
        stringWriter.Dispose(); //just dispose stringWriter
    }
}

I recently had a similar issue, but as I was using a serializer had to adapt it as I wasn't able to set the stringWriter to null right away. This workaround avoids all CA warnings:

StringWriter stringWriter = null;
XmlWriter xmlWriter = null;
string serializedValue = null;

try
{
    XmlSerializer xmlserializer = new XmlSerializer(typeof(T));
    stringWriter = new StringWriter();

    xmlWriter = XmlWriter.Create(stringWriter);
    xmlserializer.Serialize(xmlWriter, value);
    xmlWriter.Flush();
    serializedValue = stringWriter.ToString();
}
finally
{
    if (xmlWriter != null) //Both objects need disposed 
    {
        xmlWriter.Dispose(); //stringWriter will dispose automatically too
    }
    else if (stringWriter != null) //XmlWriter failed to create
    {
        stringWriter.Dispose(); //just dispose stringWriter
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文