首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >代码分析规则CA2000 / CA2202

代码分析规则CA2000 / CA2202
EN

Stack Overflow用户
提问于 2012-04-13 19:09:59
回答 3查看 1.9K关注 0票数 6

我试图确保我的编码遵循对象的正确处理,所以我将这些规则作为错误来执行。但是我在使用这段代码时遇到了问题。

代码语言:javascript
复制
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Xml;

class MyClass
{  
    public String ToXml()
    {
        var objSerializer = 
            new DataContractSerializer(GetType());
        var objStream = new MemoryStream();
        StreamReader objReader;

        String strResult;
        try
        {
            // Serialize the object
            objSerializer.WriteObject(objStream, this);

            // Move to start of stream to read out contents
            objStream.Seek(0, SeekOrigin.Begin);

            objReader = new StreamReader(objStream);

            try
            {
                // Read Contents into a string
                strResult = objReader.ReadToEnd();
            }
            finally
            {
                objReader.Dispose();
            }
        }
        finally
        {
            if (objStream != null)
            {
                // objStream.Dispose();
            }
        }

        return strResult;
    }
}

如果我注释掉了objStream.Dispose(),我会得到CA2000,因为我没有处理这个对象,但是如果我删除了注释,它就会说我正在处理不止一次。

还有什么在处理这个对象呢?或者我只是在处理多个流时做错了?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-02-20 16:49:30

这种情况现在也一直困扰着我。每隔几年,我就决定通过运行fxcop或Visual Studio中现在内置的代码分析来更新自己的代码分析“规则”。

我最初写了这段代码,认为我是一个好公民,因为我正确地使用了usings来处理:

代码语言:javascript
复制
using (MemoryStream msDecrypt = new MemoryStream())
{
    using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Write))
    {
        csDecrypt.Write(eop.m_Ciphertext, 0, eop.m_Ciphertext.Length);
    }

    decrypted = msDecrypt.ToArray();
}

这段代码会导致CA2202 "Do not dispose objects multiple times“,这条规则最大的讽刺之处在于,它实际上并不是关于你的代码的问题,而是保护你在其他代码中的问题。微软一直有大量关于如何实现Dispose模式(http://msdn.microsoft.com/en-us/library/b1yfkh5e(v=vs.110).aspx )的文档。但是,通过查看此代码分析规则(http://msdn.microsoft.com/en-us/library/ms182334.aspx)的详细信息,它揭示了此规则的用途

“正确实现的Dispose方法可以多次调用,而不会引发异常。但是,这是不能保证的,为了避免生成System.ObjectDisposedException,您不应该对对象多次调用Dispose。”

简而言之,这条规则就是为了保护自己不受那些不遵守规则的人的伤害。

很自然地,我修改了代码,使其看起来像这样:

代码语言:javascript
复制
MemoryStream msDecrypt = new MemoryStream()    
//using (MemoryStream msDecrypt = new MemoryStream())
//{
    using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Write))
    {
        csDecrypt.Write(eop.m_Ciphertext, 0, eop.m_Ciphertext.Length);
    }

    decrypted = msDecrypt.ToArray();
//}

现在这个堆栈溢出帖子上的每个人都痛苦地意识到了新的问题,我们的朋友CA2000“在失去作用域之前处置对象” ...因此,在这一点上,我只是掌心了一分钟。我在谷歌上搜索了一下,找到了这篇文章。这时我意识到,要通过这两个CA规则,您需要确保所有代码分支都只处理一次。所以我开始做这件事,一旦你意识到这是你需要做的,这并不是一个困难的问题。

自然而然,代码演变成这样:

代码语言:javascript
复制
MemoryStream msDecrypt = null;
CryptoStream csDecrypt = null;

try
{    
    msDecrypt = new MemoryStream();
    csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Write);

    csDecrypt.Write(eop.m_Ciphertext, 0, eop.m_Ciphertext.Length);
    csDecrypt.FlushFinalBlock();
    decrypted = msDecrypt.ToArray();
}
finally
{
    if (csDecrypt != null)
    {
        csDecrypt.Dispose();
    }
    else if (msDecrypt != null)
    {
        msDecrypt.Dispose();
    }

}

最后,我的代码没有产生CA2000或CA2202。这个故事的寓意是,由于代码分析规则已经以这种方式发展,USING语句的价值比过去少了很多。

有几种不同的方法可以编写代码来实现这一点,我只是选择了一种不会将显式调用与使用语句混合在一起的方法,因为我相信这样会更容易阅读,并且以一种结构上的方式来防止某人只是去包装另一个使用它,从而在不知不觉中导致了最初的问题。

票数 8
EN

Stack Overflow用户

发布于 2012-04-13 19:17:28

如果您释放了StreamReader,那么您也就释放了基础流。

如果您注释掉了objStream.Dispose(),那么您甚至可能会在到达嵌套的try块之前遇到抛出异常的情况-这将导致您的流得不到处理。

这里有一个很好的解释:Does disposing streamreader close the stream?

票数 1
EN

Stack Overflow用户

发布于 2012-04-13 19:20:27

这不是答案,但您可能会发现下面的代码更具可读性:

代码语言:javascript
复制
public String ToXml()
{
    var objSerializer =
        new DataContractSerializer(GetType());

    using (var objStream = new MemoryStream())
    {
        //  Serialize the object
        objSerializer.WriteObject(objStream, this);

        // Move to start of stream to read 
        // out contents
        objStream.Seek(0, SeekOrigin.Begin);

        using (var objReader =
            new StreamReader(objStream))
        {
            // Read Contents into a string
            retirm objReader.ReadToEnd();
        }
    }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10139718

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档