【问题标题】:Why does ((IList<T>)array).ReadOnly = True but ((IList)array).ReadOnly = False? [duplicate]为什么 ((IList<T>)array).ReadOnly = True 但 ((IList)array).ReadOnly = False? [复制]
【发布时间】:2014-10-20 21:36:55
【问题描述】:

我知道在 .NET 中,所有数组都派生自 System.Array,并且 System.Array 类实现 IListICollectionIEnumerable。实际的数组类型也实现了IList&lt;T&gt;ICollection&lt;T&gt;IEnumerable&lt;T&gt;

这意味着,例如,如果您有一个String[],那么该String[] 对象也是一个System.Collections.IList 和一个System.Collections.Generic.IList&lt;String&gt;;。

不难看出为什么这些 IList 会被视为“只读”,但令人惊讶的是......

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

在这两种情况下,尝试通过 Remove()RemoveAt() 方法删除项目都会导致 NotSupportedException。这表明这两个表达式都对应于 ReadOnly 列表,但 IList 的 ReadOnly 属性没有返回预期值。

怎么会?

【问题讨论】:

  • 我怀疑 Remove() 和 RemoveAt() 会抛出异常,因为这些操作意味着调整底层列表的大小,而 Resize 方法之外的数组不支持这一点 - 但这并不能回答您的主要问题问题。
  • @ErikForbes 认为你是对的。 Add on IList 即使显然不是只读的,也会抛出 Collection was of a fixed size 的 Not Supported 异常
  • 是的,我认为任何隐式更改底层数组大小的操作都会因该异常而失败。
  • @TyCobb 它声称对IList&lt;T&gt; 的强制转换正在实例化ReadOnlyCollection&lt;T&gt;,这是错误且具有误导性的。

标签: c# .net arrays generics


【解决方案1】:

来自MSDN

Array 实现 IsReadOnly 属性,因为它是 System.Collections.IList 接口。只读数组 不允许添加、删除或修改后的元素 数组已创建。

如果您需要只读集合,请使用 System.Collections 类 实现了 System.Collections.IList 接口。

如果将数组转换或转换为 IList 接口对象,则 IList.IsReadOnly 属性返回 false。但是,如果您施放或 将数组转换为 IList 接口,IsReadOnly 属性 返回真。

这里的只读意味着数组中的项目不能被修改,这就是它返回false的原因。

也可以看看Array.IsReadOnly inconsistent depending on interface implementation

【讨论】:

  • 虽然我很欣赏你只是引用,但“只读数组”这句话对我来说毫无意义......唯一不可变的数组是一个空数组。 All 数组允许在创建数组后修改元素。我的回答给出了一个修改所谓的只读列表的例子。 Array.IsReadOnly 仅说明了 IListIList&lt;T&gt; 实现之间的不一致。对我来说仍然像一个错误。
【解决方案2】:

这对我来说似乎是一个普通的错误:

  • 它显然不是只读的,因为索引器允许对其进行修改
  • 没有执行到任何其他类型的对象的转换

请注意,您不需要强制转换 - 存在隐式转换:

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&lt;T&gt;.IsReadOnlyIList&lt;T&gt; 继承自该属性)是documented

只读集合不允许在集合创建后添加、删除或修改元素。

虽然数组不允许添加或删除元素,但显然确实允许修改。

【讨论】:

  • IsReadOnly 不够精细,无法在此处指示只读级别。也许他们应该有CanAddElementsCanRemoveElementsCanModifyElements等方法。唉。
  • Marius 提供的 MSDN 链接表明这不是一个错误 - 尽管根据 T[] 是否强制转换为 @987654331,为什么 IsReadOnly 应该具有不同的值没有任何意义@ 或 IList&lt;T&gt;.
  • 我认为这两种演员在实现上的差异是 Jon 所指的错误。
  • @TimothyShields:我不认为它实际上表明了这一点。这句话对我没有任何意义。
  • @supercat:这正是我之前提到的问题。基本上IsReadOnly 并没有真正给你任何有用的东西,即使你信以为真。无论如何,我认为我们在这里过度扩展了 cmets。我仍然认为它的设计很糟糕,并且根据糟糕的文档,数组的实现被破坏了。
猜你喜欢
  • 2010-10-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-10
相关资源
最近更新 更多