类型化数组实现System.Collections.IList
和System.Collections.Generic.ICollection<T>
接口,它们都有自己的IsReadOnly
属性。但到底发生了什么呢?
var array = new int[10];
Console.WriteLine(array.IsReadOnly); // prints "False"
var list = (System.Collections.IList)array;
Console.WriteLine(list.IsReadOnly); // prints "False"
var collection = (System.Collections.Generic.ICollection<int>)array;
Console.WriteLine(collection.IsReadOnly); // prints "True"
数组的IList
视图的行为与我期望的一样,返回与数组本身相同,但数组的ICollection<T>
视图返回true。
这种行为是否有任何合理的解释,还是编译器/ CLR错误? (如果是后者,我真的会感到惊讶,因为你会想象之前会发现这种情况,但这是违反直觉的,我无法想到解释可能是什么......)。
我正在使用C#3.0 / .NET 3.5 SP1。
答案 0 :(得分:6)
IList是该家族的后裔 ICollection接口是基础 所有非通用列表的接口。 IList实现分为三个 类别:只读,固定大小和 大小可变的。只读IList 无法修改。固定大小的IList 不允许添加或删除 元素,但它允许 修改现有元素。一个 可变大小的IList允许 添加,删除和修改 元件。
ICollection&lt; T&gt;接口没有索引器,因此固定大小的ICollection&lt; T&gt;是自动只读 - 无法修改现有项目。
可能ICollection&lt; T&gt; .IsFixedSize将是一个比ICollection&lt; T&gt; .IsReadOnly更好的属性名称,但两者都意味着相同的东西 - 无法添加或删除元素,即与IList.IsFixedSize相同。
数组是固定大小的列表,但由于元素可以修改,因此不是只读的。
作为ICollection&lt; T&gt;,它是只读的,因为ICollection&lt; T&gt;无法修改元素。
这可能看起来令人困惑,但它是一致和合乎逻辑的。
稍微不一致的是通用IList&lt; T&gt;。 interface具有从ICollection&lt; T&gt;继承的IsReadOnly属性。因此,其语义与非通用的IList.IsReadOnly不同。我想设计师已经意识到这种不一致性,但出于向后兼容的原因,我们无法返回并更改非通用IList的语义。
总而言之,IList可以是:
可变大小。
IList.IsFixedSize = false
IList.IsReadOnly = false
ICollection&lt; T&gt; .IsReadOnly = false
固定大小(但可以修改元素,例如数组)
IList.IsFixedSize = true
IList.IsReadOnly = false
ICollection&lt; T&gt; .IsReadOnly = true
只读(无法修改元素)
IList.IsFixedSize = true
IList.IsReadOnly = true
ICollection&lt; T&gt; .IsReadOnly = true
答案 1 :(得分:4)
这一决定充满了痛苦,正如对feedback article的评论中所表明的那样。
答案 2 :(得分:0)
此行为的原因归结为具有2个IsReadOnly属性的System.Array
第一个是类型数组的普通属性。此属性满足IList接口的IsReadOnly属性。无论出于什么原因,在CLR的1.0中,他们认为该属性应该返回true。
第二个是类型ICollection<T>
的显式属性实现(实际上由CLR IIRC实现)。在这种情况下,IsReadOnly返回true,因为类型Array
无法满足ICollection<T>
的变异方法,例如Add,Clear等...
真正的问题是为什么版本之间的变化?我实际上并不知道,但我的猜测是作者确定将Array
视为只读时更合适,因为它被视为一个单独的集合。虽然它可以满足部分可变方法,但它无法满足所有这些方法。因此,将它视为只读和可变是更安全的。
答案 3 :(得分:0)
来自Array Class的文档:
在.NET Framework 2.0版中,Array类实现了
System.Collections.Generic.IList<T>
,System.Collections.Generic.ICollection<T>
,和System.Collections.Generic.IEnumerable<T>
通用接口。该 实现被提供给数组 在运行时,因此不是 对文档构建可见 工具。结果,通用 接口不会出现在 Array的声明语法 上课,并没有参考 接口成员的主题 只能通过将数组转换为 通用接口类型(显式 接口实现)。 关键 当你施展时要注意的事情 数组到这些接口之一是 添加,插入或的成员 删除元素抛出NotSupportedException
。
因此,由于泛型集合不支持添加,插入或删除,IsReadOnly
返回true。
至于为什么System.Collections.IList
没有返回false?我猜是
var array = new int[10];
Console.WriteLine(array.IsReadOnly); // prints "True"
array[0] = 5; // WTF? This is readonly.
不是他们想要看到的。当他们在v2中添加泛型接口时,只能在数组被转换时调用它们,因此对于更有意义的那些返回true。