Generic interfaces, IsReadOnly, IsFixedSize, and array


Peter Golde recently posted about the IsReadOnly and IsFixedSize change we made to the generic collection interfaces.There are also several other discussions around the net on this topic. I thought I write up something to explain the motivation and our thinking on this.


We decided that there are really not that many fixed size data structures that are not read only. In fact, we only have one – the array. We think that having a property on a very commonly implemented interface that is useful in only one case is not the right thing to do. So we decided to remove IsFixedSize. If we see a need for this in the future, we will add an interface called something like IIndexerSettable and implement it on fixed size structures.


We also decided that arrays will return true from IsReadOnly, but will actually allow setting values using the indexer (which we are trying to fix in RTM as it does not work today). In other words, the IsFixedSize and IsReadOnly properties are now changed to IsReadOnly and “is Array”, like in the following example:
 void EitherAddOrSet(IList<int> list, int newValue){
    if(!list.IsReadOnly) list.Add(newValue);
    else if(list is int[]) list[0] = newValue;
}


… oh, the IIndexerSettable interface mentioned above would work the following (and would make the EitherAddOrSet routine more general):


void EitherAddOrSet(IList<int> list, int newValue){
    if(!list.IsReadOnly) list.Add(newValue);
    else if(list is IIndexerSettable) list[0] = newValue;
}

Comments (10)

  1. Mark says:

    "We also decided that arrays will return false from IsReadOnly, but will actually allow setting values using the indexer" … Should that be "return TRUE"? or am I missing the point?

  2. TheMuuj says:

    Thank you for reconsidering.

    It’s not like you’re throwing an exception in a case where the contract indicates the method/property/indexer should work.

    You’re NOT throwing an exception when setting, even though the list is supposedly read-only. Why would anyone in their right mind check for IsReadOnly==true only to set a value, expecting an exception? Allowing array sets may not follow the letter of the contract, but it certainly doesn’t break it.

  3. Krzysztof Cwalina says:

    Mark, you are right. It should say "We also decided that arrays will return true from IsReadOnly". I fixed that in th epost.

  4. Ruben says:

    Thank you. I liked Peter’s CanAddRemove approach better than IsReadOnly, but it will do just as well (and won’t break Beta 2 to RTM scenarios).

    I’m still trying to think of real scenarios where IsReadOnly would be useful at runtime. I mean, say you’d want to add an element to an ICollection, so you’d check whether IsReadOnly is false. So far so good. But what if it wasn’t? Throw an exception? Hey, wait a minute, the ICollection<X>.Add already does that! I’m obviously missing something here…

  5. Krzysztof Cwalina says:

    IsReadOnly is mainly for scenarios like databinding. Databinding is one way if the property returns true and two-way if it returns false.

  6. TheMuuj says:

    Right…databinding. Which is being saying you’re read-only when you are not completely read-only is not the end of the world.

    Databinding was my argument for putting IsFixedSized into generic collections/lists. A generically-written list editor could determine whether Add/Remove buttons were visible.

    But when I made this argument I did not really realize that there’s no good place to put it. Specifically, it makes absolutely no sense on ICollection<T>, where Add and Remove are, and where IsReadOnly determines whether those methods are valid, and putting it on IList<T> would not work because ICollection<T>.IsReadOnly would be true for fixed-sized lists.

    For now, checking for arrays manually seems to be a good approach, since I rarely have fixed-sized, read-write lists (not out of the question, but rare). For edge-cases, attempting to cast to IList (non-generic) and checking IsFixedSized just to be extra sure might also work, seeing as many generic collections will implement the non-generic interfaces.

  7. On utilise tous les jours les interfaces IEnumerable, ICollection, IList quand on d&#233;veloppe en .Net,…

  8. On utilise tous les jours les interfaces IEnumerable, ICollection, IList quand on développe en .Net,