Today I had a simple question that ended up having a bit of a complex answer: how does one implement
The fundamental problem is that there’s more than one definition of “read-only”. Various collection types permit different types of updates. Generally, updates fall into one of two categories:
- An update that changes the value of an element already in the collection, and does not change the number of elements in the collection. e.g., the index setter.
- An update that changes the number of values in the collection, but does not change any of the values of the elements in the collection. e.g.,
I Googled for the proper semantics to use, and was able to find three decent sources of information: a StackOverflow question on the Contract of
ICollection<T>.IsReadOnly, a blog post by Peter Golde titled “
IsReadOnly”, and a blog post by Krzysztof Cwalina on “Generic interfaces,
IsFixedSize, and array”. From the (older) blog posts and some quick tests on array behavior, I’ve reached the conclusions below regarding the history and current state of the
The Traditional Interpretation
The value of
false if either type of update is allowed. It is only set to
true if both types of updates are not allowed.
The built-in array type (which only allows one type of update) honors this interpretation by returning
The Modern Interpretation
It appears that with .NET 2.0, the meaning of
IsReadOnly has changed. It should now be
true if either type of update is not allowed. It is only set to
false if both types of updates are allowed.
Interestingly, the built-in array type honors this interpretation as well. It returns true for
IsReadOnly (but only if accessed through a generic interface):
Presumably, any new list types that implement
IList as well as
IList<T> may need to return different values for
IList<T>.IsReadOnly. This is confusing, to say the least.
Identical Documentation; Confusing Behavior
As of the time of blog post, the Microsoft documentation for
ICollection<T>.IsReadOnly are nearly identical, ignoring the fact that the semantics are quite different:
IList.IsReadOnly: “A collection that is read-only does not allow the addition, removal, or modification of elements after the collection is created.”
ICollection\<T>.IsReadOnly: “A collection that is read-only does not allow the addition, removal, or modification of elements after the collection is created.”
Furthermore, the behavior of the common array class is confusing, especially in light of the current Microsoft documentation for
Array.IsReadOnly: “This property is always false for all arrays.”
Conclusion: Does Anyone Care?
This blog post has been an attempt to sort out the proper way of implementing
IsReadOnly. However, due to the complexity of the semantics, it seems unlikely that any client code is actually using it correctly.
For future code, I recommend only implementing
IList<T> with the modern interpretation, and not implementing
IList. If one does need
IList, however (e.g., for binding purposes), then they should implement both interpretations.