| 屬性 | 值 |
|---|---|
| 規則識別碼 | CA2227 |
| 職稱 | 集合屬性應該為唯讀 |
| 類別 | 使用方式 |
| 修正是造成中斷還是不中斷 | 中斷 |
| 在 .NET 10 中預設啟用 | 否 |
| 適用語言 | C# 與 Visual Basic |
原因
外部可見且可寫入的屬性是一種實作 System.Collections.ICollection 的型別。 此規則會忽略數位、索引器(名稱為 'Item' 的屬性)、不可變的集合、只讀集合和許可權集合。
規則描述
可寫的集合屬性讓使用者可以用完全不同的集合取代該集合。 唯讀或 僅初始化 的特性防止集合被替換,但仍允許設定個別成員。 若目標是替換集合,首選的設計模式是包含移除所有元素的方法,以及重新填充集合的方法。 如需此模式的範例,請參閱 類別Clear的 AddRange 和 System.Collections.ArrayList 方法。
二進位和 XML 串行化都支援集合的唯讀屬性。 這個 System.Xml.Serialization.XmlSerializer 類別對於實作 ICollection 和 System.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
如需詳細資訊,請參閱 如何隱藏程式代碼分析警告。
範例
以下範例展示了具有可寫集合屬性的型別,以及如何直接替換該集合。 它也展示了使用 Clear 和 AddRange 方法替換唯讀集合屬性的首選方式。
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