Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does ((IList<T>)array).ReadOnly = True but ((IList)array).ReadOnly = False? [duplicate]

I know that in .NET all arrays derive from System.Array and that the System.Array class implements IList, ICollection and IEnumerable. Actual array types also implement IList<T>, ICollection<T> and IEnumerable<T>.

This means that if you have, for example, a String[], then that String[] object is also a System.Collections.IList and a System.Collections.Generic.IList<String>;.

It's not hard to see why those IList's would be considered "ReadOnly", but surprisingly...

String[] array = new String[0];
Console.WriteLine(((IList<String>)array).IsReadOnly); // True
Console.WriteLine(((IList)array).IsReadOnly); // False!

In both cases, attempts to remove items via the Remove() and RemoveAt() methods results in a NotSupportedException. This would suggest that both expressions correspond to ReadOnly lists, but IList's ReadOnly property does not return the expected value.

How come?

like image 217
J Smith Avatar asked Oct 20 '14 21:10

J Smith


2 Answers

From MSDN:

Array implements the IsReadOnly property because it is required by the System.Collections.IList interface. An array that is read-only does not allow the addition, removal, or modification of elements after the array is created.

If you require a read-only collection, use a System.Collections class that implements the System.Collections.IList interface.

If you cast or convert an array to an IList interface object, the IList.IsReadOnly property returns false. However, if you cast or convert an array to a IList<T> interface, the IsReadOnly property returns true.

Read-only here means that the items in the array cannot be modified and that's why it returns false.

Also have a look at Array.IsReadOnly inconsistent depending on interface implementation.

like image 134
Marius Bancila Avatar answered Oct 20 '22 17:10

Marius Bancila


This looks like a plain bug to me:

  • It clearly isn't read-only, as the indexer allows it to be modified
  • It is not performing a conversion to any other kind of object

Note that you don't need to cast - there's an implicit conversion:

using System;
using System.Collections.Generic;

class Test
{
    static void Main()
    {
        string[] array = new string[1];
        IList<string> list = array;
        Console.WriteLine(object.ReferenceEquals(array, list));
        Console.WriteLine(list.IsReadOnly);
        list[0] = "foo";
        Console.WriteLine(list[0]);
    }
}

ICollection<T>.IsReadOnly (which IList<T> inherits the property from) is documented as:

A collection that is read-only does not allow the addition, removal, or modification of elements after the collection is created.

While an array doesn't allow the addition or removal of elements, it clearly does allow modification.

like image 12
Jon Skeet Avatar answered Oct 20 '22 17:10

Jon Skeet