MemoryStream、XmlTextWriter 和警告 4 CA2202:Microsoft.Usage

Posted

技术标签:

【中文标题】MemoryStream、XmlTextWriter 和警告 4 CA2202:Microsoft.Usage【英文标题】:MemoryStream, XmlTextWriter and Warning 4 CA2202 : Microsoft.Usage 【发布时间】:2010-12-21 20:51:58 【问题描述】:

Visual Studio 2010 Ultimate 中的运行代码分析命令在看到带有MemoryStreamXmlTextWriter 的特定模式时会返回警告。

这是警告:

警告 7 CA2202:Microsoft.Usage: 对象 'ms' 可以被处理多个 一次方法 'KinteWritePages.GetXPathDocument(DbConnection)'。 为了避免产生 System.ObjectDisposedException 你 不应调用 Dispose 多个 对象上的时间。:行: 421 C:\Visual Studio 2010\Projects\Songhay.DataAccess.KinteWritePages\KinteWritePages.cs 421 Songhay.DataAccess.KinteWritePages

这是表格:

static XPathDocument GetXPathDocument(DbConnection connection)

    XPathDocument xpDoc = null;
    var ms = new MemoryStream();
    try
    
        using(XmlTextWriter writer = new XmlTextWriter(ms, Encoding.UTF8))
        
            using(DbDataReader reader = CommonReader.GetReader(connection, Resources.KinteRssSql))
            

                writer.WriteStartDocument();
                writer.WriteStartElement("data");

                do
                
                    while(reader.Read())
                    
                        writer.WriteStartElement("item");
                        for(int i = 0; i < reader.FieldCount; i++)
                        
                            writer.WriteRaw(String.Format("<0>1</0>", reader.GetName(i), reader[i].ToString()));
                        
                        writer.WriteFullEndElement();
                    

                 while(reader.NextResult());

                writer.WriteFullEndElement();
                writer.WriteEndDocument();

                writer.Flush();
                ms.Position = 0;

                xpDoc = new XPathDocument(ms);
            
        

    
    finally
    
        ms.Dispose();
    

    return xpDoc;

此表单会产生相同类型的警告:

XPathDocument xpDoc = null;
using(var ms = new MemoryStream())

    using(XmlTextWriter writer = new XmlTextWriter(ms, Encoding.UTF8))
    
        using(DbDataReader reader = CommonReader.GetReader(connection, Resources.KinteRssSql))
        
            //...
        
    



return xpDoc;

顺便说一句,下面的表格会产生另一个警告:

XPathDocument xpDoc = null;
var ms = new MemoryStream();
using(XmlTextWriter writer = new XmlTextWriter(ms, Encoding.UTF8))

    using(DbDataReader reader = CommonReader.GetReader(connection, Resources.KinteRssSql))
    
        //...
    


return xpDoc;

以上产生警告:

警告 7 CA2000: Microsoft.Reliability:方法中 'KinteWritePages.GetXPathDocument(DbConnection)', 对象 'ms' 并未全部处置 异常路径。称呼 System.IDisposable.Dispose 对象 'ms' 在所有对它的引用之前 超出范围。 C:\Visual Studio 2010\Projects\Songhay.DataAccess.KinteWritePages\KinteWritePages.cs 383 Songhay.DataAccess.KinteWritePages

除了以下之外,我还有哪些选择?:

禁止警告 CA2202。 禁止警告 CA2000 并希望 微软正在处理 MemoryStream(因为 Reflector 没有向我显示源代码)。 重写我的旧代码以识别 精彩的XDocument 和 LINQ to XML。

【问题讨论】:

C# CA2000:Dispose objects before losing scope using FileStream/XmlTextReader 的可能重复项 【参考方案1】:

首先,你不应该使用new XmlTextWriter()。自 .NET 2.0 以来,它已被弃用。请改用XmlWriter.Create()

其次,ms 的赋值应该在 using 块中:

using (var ms = new MemoryStream())

    using (var writer = XmlWriter.Create(ms))
    
        // ...
    

我相信警告是正确的。 MemoryStream 可以在 XmlTextWriter 被释放时被释放,然后在“finally”块中再次被释放。

【讨论】:

这里需要注意的一点:在更高版本的 .Net Framework 中,XmlWriter.Create(stream) 创建了一个 XmlWriter.Settings.CloseOutput 为“假”的对象,您确实需要处理MemoryStream 分开。问题是 CA2202 仍然被引发,即使 Dispose() 只在底层流上被调用一次。我只是压制了警告并将其证明为误报。 @russell 这很有意义。如果您将现有流传递给它,则它属于您,并且您知道何时关闭它。【参考方案2】:

如果这是我的代码库,我会禁止它。代码分析可以警告您潜在的问题,只要您(以及团队中的其他所有人,包括所有未来的开发人员)意识到潜在的问题,您就可以了。 Here's Microsoft's way 避免这个问题(在我看来,这违背了using() 的目的。

在类似的注释中,here's some code 向您展示了您可能如何实际遇到此修复的错误。第一个代码块写入MemoryStream 会关闭StreamWriter,然后尝试在另一个StreamReader 中读取它。不幸的是,StreamWriter 上的Dispose() 也关闭了MemoryStream。解决方案是从StreamWriter 中创建StreamReader

【讨论】:

以上是关于MemoryStream、XmlTextWriter 和警告 4 CA2202:Microsoft.Usage的主要内容,如果未能解决你的问题,请参考以下文章

MemoryStream - 无法访问已关闭的流

为啥 MemoryStream.GetBuffer() 总是抛出?

不同的线程访问 MemoryStream

来自 HttpContent 的 MemoryStream 无需复制

如何从 .NET 中的流中获取 MemoryStream?

将 MemoryStream 文件存储到 Azure Blob