簡體   English   中英

代碼分析規則CA2000 / CA2202

[英]Code Anlysis Rule CA2000 / CA2202

我正在努力確保我的編碼遵循正確的對象處理方式,因此我將這些規則強制執行為錯誤。 但我在使用這段代碼時遇到了麻煩

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,因為我沒有處理該對象,但是如果我刪除了注釋,那么我說我不止一次處理。

還有什么處理對象? 或者我在處理多個流時只是做錯了嗎?

這種情況現在也讓我煩惱。 每隔幾年,我決定通過在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();
}

這段代碼會導致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();
//}

現在每個人都在這個堆棧溢出的帖子上痛苦地意識到了這個新問題,我們的朋友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();
    }

}

最后,我的代碼沒有導致CA2000或CA2202。 故事的寓意在於,代碼分析規則以這種方式發展,USING語句的價值遠低於過去。

有幾種不同的方法可以編寫代碼來實現這個功能,我只是選擇了一種不會將顯式調用與dispose混合使用的方式,因為我認為這樣做更簡單易讀和結構化這會阻止某人在周圍使用它來包裝另一個人,從而在不知情的情況下導致最初的問題。

如果丟棄StreamReader,則還要處理基礎流。

如果你注釋掉objStream.Dispose(),那么在你進入嵌套的try塊之前你會遇到拋出異常的可能性 - 這將導致你的流沒有被處理掉。

這里有一個很好的解釋: 處理streamreader會關閉流嗎?

這不是答案,但您可能會發現此代碼更具可讀性:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM