代码分析规则CA2000/CA2202

Dre*_*ker 6 c# code-analysis stylecop

我正在努力确保我的编码遵循正确的对象处理方式,因此我将这些规则强制执行为错误.但我在使用这段代码时遇到了麻烦

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我发表评论,objStream.Dispose()我得到了CA2000,因为我没有处理该对象,但如果我删除了评论,那么我说我处置不止一次.

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

Mar*_*p51 8

这种情况现在也让我烦恼.每隔几年,我决定通过在Visual Studio中运行fxcop或现在的内置代码分析来刷新自己的代码分析"规则".

我最初编写这段代码,认为我是一个善于使用uses处理的好公民:

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();
}
Run Code Online (Sandbox Code Playgroud)

这段代码会导致CA2202"不要多次丢弃对象"这条规则的讽刺之处在于,它并不是关于代码的问题,而是保护您关于其他代码中的问题.微软一直有大量关于如何实现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."

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

当然我修改了代码看起来像这样:

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();
//}
Run Code Online (Sandbox Code Playgroud)

现在这个堆叠溢出帖子的每个人都痛苦地意识到了这个新问题,我们的朋友CA2000"在失去范围之前处理对象" ......所以在这一点上我只是面对了一分钟.做过几次谷歌搜索,发现这篇文章.这时候,我明白了,通过两个CA的规则,你需要确保一切所有代码分支布置一次且仅一次.所以我开始这样做,一旦你意识到这是你需要做的事情,这不是一个难题.

当然,代码演变为:

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();
    }

}
Run Code Online (Sandbox Code Playgroud)

最后,我的代码没有导致CA2000或CA2202.故事的寓意在于,代码分析规则以这种方式发展,USING语句的价值远低于过去.

有几种不同的方法可以编写代码来实现这个功能,我只是选择了一种不会将显式调用与dispose混合使用的方法,因为我认为这样做更简单易读和结构化这会阻止某人在周围使用它来包装另一个人,从而在不知情的情况下导致最初的问题.

  • 虽然在一般情况下看起来技术上是正确的,但现实世界的使用完全没有问题,因为整齐的"使用"结构(即成功时处理两次).因此,为了便于阅读,我只有在知道该类正确处理它时才会正确地抑制此错误.我认为这是MS代码分析警告的重点(让我们考虑一下).最好的解决方案是让代码分析规则引擎自己发现它; 给我们一些方法来声明这个(例如代码契约).无论如何,我投了你的答案,因为这是一个很好的解释,必须加以考虑. (2认同)