如何修复CA2202警告?

3

以下是我用来解析XML的方法。代码分析时出现了CA2202警告,提示对象mStream可能会被多次处理,不应该调用dispose超过一次。如何解决这个警告?

public static String PrintXML(String XML)
    {
        String result = "";
        string[] xmlSeperators = new string[] { "<?" };
        string[] splitResults = new string[2];

        if (!String.IsNullOrEmpty(XML))
        {
            using (MemoryStream mStream = new MemoryStream())
            {
                using (XmlTextWriter writer = new XmlTextWriter(mStream, Encoding.Unicode))
                {
                    XmlDocument document = new XmlDocument();
                    try
                    {
                        // Load the XmlDocument with the XML.
                        //Check if it is only XML 
                        if (XML.StartsWith("<?"))
                        {
                            document.LoadXml(XML);
                        }
                        else
                        {
                            //Split the string appended before XML
                            splitResults = XML.Split(xmlSeperators, 2, StringSplitOptions.None);
                            if (splitResults.Length > 1)
                            {
                                string d = "<?" + splitResults[1];
                                document.LoadXml(d);
                            }
                        }
                        writer.Formatting = Formatting.Indented;
                        // Write the XML into a formatting XmlTextWriter
                        document.WriteContentTo(writer);
                        //xx.WriteTo(writer);
                        writer.Flush();
                        mStream.Flush();
                        // Have to rewind the MemoryStream in order to read its contents.
                        mStream.Position = 0;
                        // Read MemoryStream contents into a StreamReader.
                        StreamReader sReader = new StreamReader(mStream);
                        // Extract the text from the StreamReader.
                        String FormattedXML = sReader.ReadToEnd();

                        if (splitResults[0] != null)
                        {
                            result = splitResults[0] + "\n" + FormattedXML;
                        }
                        else
                        {
                            result = FormattedXML;
                        }
                    }
                    catch (XmlException xe)
                    {
                        Log.Error(xe);
                        throw;
                    }                        
                }                   
            }
        }
        return result;
    }

2
不幸的是,在.NET 4.5中,XmlTextWriter没有像StreamWriter一样的重载(http://msdn.microsoft.com/en-us/library/gg712853(v=vs.110).aspx),所以你必须按照Habib所说的去做。通常我会像这样做`new XmlTextWriter(new MemoryStream(), ...`以明确XmlTextWriter拥有该流--但实际上并不适用于你的示例,因为你在创建XmlTextWriter之后使用了该流。 - Peter Ritchie
3个回答

3
得到这个警告的原因是 XmlTextWriter.Dispose() 会确保底层的 MemoryStream 对象也被处理。因此,当 MemoryStreamusing 作用域结束时,它将尝试处理 MemoryStream 对象,因此出现警告。 using 块编译为 try-finally 块。你代码中内部的 using 块会调用 writer 上的 Dispose。这会调用 mStream 上的 Dispose。在内部 using 块的控制流程退出后,外部的 using 块将尝试处理对象 writer,但由于已经处理过一次,所以在代码分析工具上会出现警告。
为了消除这个警告,你可以删除第一个 using 语句并使用 try-finally 块。但要记得在进入第二个 using 语句时立即将 mStream 设置为 null。这已经在 CA2202: Do not dispose objects multiple times 中解释过了。
你的代码应该像下面这样:
public static String PrintXML(String XML)
{
    String result = "";
    string[] xmlSeperators = new string[] { "<?" };
    string[] splitResults = new string[2];

    if (!String.IsNullOrEmpty(XML))
    {
        MemoryStream mStream  = null;
        try
        {
            mStream = new MemoryStream();
            using (XmlTextWriter writer = new XmlTextWriter(mStream, Encoding.Unicode))
            {
                mStream = null; // important 
                XmlDocument document = new XmlDocument();
                try
                {
                    // Load the XmlDocument with the XML.
                    //Check if it is only XML 
                    if (XML.StartsWith("<?"))
                    {
                        document.LoadXml(XML);
                    }
                    else
                    {
                        //Split the string appended before XML
                        splitResults = XML.Split(xmlSeperators, 2, StringSplitOptions.None);
                        if (splitResults.Length > 1)
                        {
                            string d = "<?" + splitResults[1];
                            document.LoadXml(d);
                        }
                    }
                    writer.Formatting = System.Xml.Formatting.Indented;
                    // Write the XML into a formatting XmlTextWriter
                    document.WriteContentTo(writer);
                    //xx.WriteTo(writer);
                    writer.Flush();
                    mStream.Flush();
                    // Have to rewind the MemoryStream in order to read its contents.
                    mStream.Position = 0;
                    // Read MemoryStream contents into a StreamReader.
                    StreamReader sReader = new StreamReader(mStream);
                    // Extract the text from the StreamReader.
                    String FormattedXML = sReader.ReadToEnd();

                    if (splitResults[0] != null)
                    {
                        result = splitResults[0] + "\n" + FormattedXML;
                    }
                    else
                    {
                        result = FormattedXML;
                    }
                }
                catch (XmlException xe)
                {
                    Log.Error(xe);
                    throw;
                }
            }
        }
        finally 
        {

            if (mStream != null)
            {
                mStream.Dispose();
            }

        }
    }
    return result;
}

1
感谢您深入的解释 :) - Rex

1
你可以像其他答案所说的那样抑制错误警告,但是实际上解决此问题的方法是在代码中仅调用一次.Dispose()方法,并且只在完成操作后才这样做。如果再次处理已处理的对象,则会引发System.ObjectDisposedException异常,但不一定如此。正确的处理方法可以多次调用一个对象,并且可能不会为您生成错误。但不能保证如此。
Microsoft的开发人员网络文档已经说明了这个问题的解决方法,
“要修复此规则的违规情况,请更改实现,以便无论代码路径如何,仅为对象调用一次Dispose。”
更多信息:http://msdn.microsoft.com/en-us/library/ms182334.aspx

0

当您有嵌套的using语句,其中内部语句包含来自外部语句的资源时,就会发生这种情况。在这种情况下,当XmlTextWriter被处理时,它将处理MemoryStream,然后外部using语句将导致其被处理第二次。

您可以通过使用try/finally手动处理MemoryStream来替换外部using语句:

MemoryStream mStream = null;
try
{
    mStream = new MemoryStream();
    using (XmlTextWriter writer = new XmlTextWriter(mStream, Encoding.Unicode))
    {
      mStream = null;
     ...
    }
}
finally
{
    if(mStream != null)
        mStream.Dispose();
}

(请参见http://msdn.microsoft.com/zh-cn/library/ms182334.aspx


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接