CA2227: Collection properties should be read only
TypeName | CollectionPropertiesShouldBeReadOnly |
CheckId | CA2227 |
Category | Microsoft.Usage |
Breaking Change | Breaking |
An externally visible writable property is a type that implements System.Collections.ICollection. Arrays, indexers (properties with the name 'Item'), and permission sets are ignored by the rule.
A writable collection property allows a user to replace the collection with a completely different collection. A read-only property stops the collection from being replaced but still allows the individual members to be set. If replacing the collection is a goal, the preferred design pattern is to include a method to remove all the elements from the collection and a method to re-populate the collection. See the Clear and AddRange methods of the System.Collections.ArrayList class for an example of this pattern.
Both binary and XML serialization support read-only properties that are collections. The System.Xml.Serialization.XmlSerializer class has specific requirements for types that implement ICollection and System.Collections.IEnumerable in order to be serializable.
The following example shows a type with a writable collection property and shows how the collection can be replaced directly. Additionally, the preferred manner of replacing a read-only collection property using Clear and AddRange methods is shown.
using System; using System.Collections; namespace UsageLibrary { public class WritableCollection { ArrayList strings; public ArrayList SomeStrings { get { return strings; } // Violates the rule. set { strings = value; } } public WritableCollection() { strings = new ArrayList( new string[] {"IEnumerable", "ICollection", "IList"} ); } } class ReplaceWritableCollection { static void Main() { ArrayList newCollection = new ArrayList( new string[] {"a", "new", "collection"} ); // strings is directly replaced with newCollection. WritableCollection collection = new WritableCollection(); collection.SomeStrings = newCollection; // newCollection is added to the cleared strings collection. collection.SomeStrings.Clear(); collection.SomeStrings.AddRange(newCollection); } } }
After having the same issue as DominicZ, I found a blog posting at
http://blog.andreloker.de/post/2009/08/07/XmlSerializer-and-automatic-collection-properties.aspx that explained that you cannot use auto-backed property and fix this issue. The property must have a backing filed and the set or private set must be removed completely (only a get, and the property is constructed using the backing field directly).
This worked for me. I was able to serialize the class after doing this.
- 3/5/2011
- poupou
- 11/11/2010
- Patrick Sheahan
I have found that if you do use a private set on the collection, the XmlSerializer with throw an exception when constructed.
System.InvalidOperationException
Unable to generate a temporary class (result=1).
error CS0200: Property or indexer 'ConsoleApplication1.Strings.Collection' cannot be assigned to -- it is read only
The following code demonstrates this:
public class MyStringCollection : Collection<string> {}
public class Strings
{
public Strings()
{
this.Collection = new MyStringCollection();
}
public MyStringCollection Collection { get; private set; }
}
class Program
{
static void Main(string[] args)
{
Strings s = new Strings();
s.Collection.Add("string1");
s.Collection.Add("string2");
s.Collection.Add("string3");
//Throws an error
XmlSerializer ser = new XmlSerializer(typeof(Strings));
StringBuilder sb = new StringBuilder();
StringWriter sw = new StringWriter(sb);
ser.Serialize(sw, s);
string text = sb.ToString();
}
}