代码之家  ›  专栏  ›  技术社区  ›  Greg Beech

array.isreadOnly不一致,具体取决于接口实现

  •  5
  • Greg Beech  · 技术社区  · 15 年前

    类型化数组实现 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。

    4 回复  |  直到 14 年前
        1
  •  4
  •   Hans Passant    15 年前

    这一决定引起了极大的痛苦,这在评论中很明显。 feedback article .

        2
  •  6
  •   to StackOverflow    15 年前

    From MSDN 以下内容:

    伊利斯特是 ICollection接口是基础 所有非通用列表的接口。 IList实现分为三个部分 类别:只读、固定大小和 可变大小。只读IList 无法修改。固定大小的ilist 不允许添加或删除 但它允许 修改现有元素。一 可变大小的ilist允许 添加、移除和修改 元素。

    ICollection<t>接口没有索引器,因此固定大小的ICollection<t>自动为只读-无法修改现有项。

    可能是ICollection<t>.IsFixedSize的属性名比ICollection<t>.IsReadOnly更好,但两者都意味着相同的内容-无法添加或删除元素,即与ilist.IsFixedSize相同。

    数组是固定大小的列表,但不是只读的,因为可以修改元素。

    作为ICollection<t>,它是只读的,因为ICollection<t>无法修改元素。

    这看起来可能令人困惑,但它是一致的和合乎逻辑的。

    稍微不一致的是,通用IList<t>接口具有继承自ICollection<t>的IsReadOnly属性,其语义因此不同于非通用IList.IsReadOnly。我认为设计者知道这种不一致性,但是由于向后兼容性的原因,无法返回并更改非通用IList的语义。

    总之,IList可以是:

    • 可变大小。

      ilist.isFixedSize=false

      ilist.isreadonly=假

      ICollection<t>.IsReadOnly=false

    • 固定大小(但可以修改元素,例如数组)

      ilist.isFixedSize=真

      ilist.isreadonly=假

      ICollection<t>.IsReadOnly=true

    • 只读(不能修改元素)

      ilist.isFixedSize=真

      ilist.isreadonly=真

      ICollection<t>.IsReadOnly=true

        3
  •  0
  •   JaredPar    15 年前

    这种行为的原因归结为 System.Array 具有2个只读属性

    第一个是类型数组的一个普通属性。此属性满足IList接口的IsReadOnly属性。无论出于何种原因,在clr的1.0中,他们认为该属性应返回true。

    第二个是类型的显式属性实现 ICollection<T> (实际由clr IIRC实现)。在这种情况下,IsReadOnly返回true,因为类型 Array 无法满足的变异方法 i收集<t> 如添加、清除等…

    真正的问题是为什么版本之间会发生变化?我不知道,但我的猜测是,作者认为更适合观察 数组 当它被视为单独的集合时为只读。虽然它可以满足部分可变方法,但不能满足全部可变方法。因此,将其视为只读与可变比较更安全。

        4
  •  0
  •   Logan5    15 年前

    从文档中 Array Class :

    在.NET Framework 2.0版中,数组类实现 System.Collections.Generic.IList<T> , System.Collections.Generic.ICollection<T> System.Collections.Generic.IEnumerable<T> 通用接口。这个 将实现提供给数组 在运行时,因此 对文档构建可见 工具。因此,一般 接口不出现在 数组的声明语法 类,没有引用 接口成员的主题 只能通过将数组强制转换为 通用接口类型(显式 接口实现)。 关键 当你在一个 其中一个接口的数组是 添加、插入或 删除元素引发 NotSupportedException .

    因此,由于泛型集合不支持添加、插入或删除, IsReadOnly 返回true。 为什么它不返回false System.Collections.IList ?我想是这样的

    var array = new int[10];
    Console.WriteLine(array.IsReadOnly); // prints "True"
    array[0] = 5; // WTF? This is readonly.
    

    不是他们想看到的。当他们在v2中添加泛型接口时,只有在数组被强制转换时才能调用这些接口,因此对于那些更合理的接口,返回true。