CA2227: 集合屬性應設為唯讀

屬性
規則識別碼 CA2227
職稱 集合屬性應該為唯讀
類別 使用方式
修正是造成中斷還是不中斷 中斷
在 .NET 10 中預設啟用
適用語言 C# 與 Visual Basic

原因

外部可見且可寫入的屬性是一種實作 System.Collections.ICollection 的型別。 此規則會忽略數位、索引器(名稱為 'Item' 的屬性)、不可變的集合、只讀集合和許可權集合。

規則描述

可寫的集合屬性讓使用者可以用完全不同的集合取代該集合。 唯讀或 僅初始化 的特性防止集合被替換,但仍允許設定個別成員。 若目標是替換集合,首選的設計模式是包含移除所有元素的方法,以及重新填充集合的方法。 如需此模式的範例,請參閱 類別ClearAddRangeSystem.Collections.ArrayList 方法。

二進位和 XML 串行化都支援集合的唯讀屬性。 這個 System.Xml.Serialization.XmlSerializer 類別對於實作 ICollectionSystem.Collections.IEnumerable 的型別有特定要求,且必須可序列化。

如何修正違規

請採用以下方法之一來修正違反此規則的行為:

  • 將屬性設為唯讀或僅限初始輸入。 唯讀或 僅初始化 的特性防止集合被替換,同時仍允許設定個別成員。 若設計需要替換收藏內容,則新增清除與重新填充收藏的方法。 此模式範例請參見 ArrayList.Clear and ArrayList.AddRange 方法。

  • 將屬性類型改為唯讀集合類型。 如果呼叫者不需要修改集合,則將屬性類型改為唯讀集合,例如 ReadOnlyCollection<T>。 此方法明確將唯讀意圖明確化於型別簽章中。

  • 將屬性類型改為執行緒安全的並行集合類型,但保留屬性為唯讀。 若設計需多個執行緒同時修改集合,則可開放一個唯讀性質(無設定器),其型別為並行集合,例如 ConcurrentBag<T>。 CA2227 是由可寫的集合屬性觸發,而非集合類型,因此該屬性仍必須是唯讀。 並行收集選項僅針對回傳集合實例的執行緒安全變異問題。

隱藏警告的時機

如果 屬性是資料傳輸物件 (DTO) 類別的一部分,您可以隱藏警告。

否則,不要壓抑這條規則的警告。

隱藏警告

如果您只想要隱藏單一違規,請將預處理器指示詞新增至原始程式檔以停用,然後重新啟用規則。

#pragma warning disable CA2227
// The code that's violating the rule is on this line.
#pragma warning restore CA2227

若要停用檔案、資料夾或專案的規則,請在組態檔中將其嚴重性設為 none

[*.{cs,vb}]
dotnet_diagnostic.CA2227.severity = none

如需詳細資訊,請參閱 如何隱藏程式代碼分析警告

範例

以下範例展示了具有可寫集合屬性的型別,以及如何直接替換該集合。 它也展示了使用 ClearAddRange 方法替換唯讀集合屬性的首選方式。

public class WritableCollection
{
    public ArrayList SomeStrings
    {
        get;

        // This set accessor violates rule CA2227.
        // To fix the code, remove this set accessor or change it to init.
        set;
    }

    public WritableCollection()
    {
        SomeStrings = new ArrayList(new string[] { "one", "two", "three" });
    }
}

class ReplaceWritableCollection
{
    static void Main2227()
    {
        ArrayList newCollection = ["a", "new", "collection"];

        WritableCollection collection = new()
        {
            // This line of code demonstrates how the entire collection
            // can be replaced by a property that's not read only.
            SomeStrings = newCollection
        };

        // If the intent is to replace an entire collection,
        // implement and/or use the Clear() and AddRange() methods instead.
        collection.SomeStrings.Clear();
        collection.SomeStrings.AddRange(newCollection);
    }
}
Public Class WritableCollection

    ' This property violates rule CA2227.
    ' To fix the code, add the ReadOnly modifier to the property:
    ' ReadOnly Property SomeStrings As ArrayList
    Property SomeStrings As ArrayList

    Sub New()
        SomeStrings = New ArrayList(New String() {"one", "two", "three"})
    End Sub

End Class

Class ViolatingVersusPreferred

    Shared Sub Main2227()
        Dim newCollection As New ArrayList(New String() {"a", "new", "collection"})

        Dim collection As New WritableCollection()

        ' This line of code demonstrates how the entire collection
        ' can be replaced by a property that's not read only.
        collection.SomeStrings = newCollection

        ' If the intent is to replace an entire collection,
        ' implement and/or use the Clear() and AddRange() methods instead.
        collection.SomeStrings.Clear()
        collection.SomeStrings.AddRange(newCollection)
    End Sub

End Class

另請參閱