【问题标题】:Why System.Array class implements IList but does not provide Add()为什么 System.Array 类实现 IList 但不提供 Add()
【发布时间】:2016-11-02 05:45:45
【问题描述】:

这段代码:

int[] myArr = { 1, 2 };
myArr.Add(3);

在构建时抛出以下错误:

错误 CS1061:“System.Array”不包含“Add”的定义,并且找不到接受“System.Array”类型的第一个参数的扩展方法“Add”(您是否缺少 using 指令或汇编参考?)

IList接口有Add()方法,但是为什么Array没有实现呢?

更新:我从答案中看到它确实明确地实现了它,好的,我明白了,谢谢,我最好坚持这个问题:

为什么Array 实际上没有提供 Add(),或者,更好的是,为什么它必须首先实现IList?除了实现IList,它可以是另一个接口(例如IArray),它可能只对IList的数组成员有用-例如。 IsFixedSizeIsReadOnlyIndexOf()...只是一个想法。

【问题讨论】:

  • 如果你把它转换成IList,你就可以调用Add(类可以实现一些接口explicitly,这意味着你只能访问(全部)将其视为该接口时的接口方法)。不过你会失望的。数组有固定的大小。
  • 那为什么语言不简单地从 Array 类签名中删除 :IList 呢?
  • 它没有。 Array 实现了IList - 但如果你想将它作为 IList 使用,你必须将它转换为该类型的变量。
  • @Damien_The_Unbeliever,抱歉我更正了这个问题,我的意思是为什么它没有删除它!
  • 这能回答你的问题吗? Why array implements IList?

标签: c# list system.array


【解决方案1】:

为什么 Array 实际上不提供 Add()?

数组的大小是固定的,所以你不能添加新元素。

维度的数量和每个维度的长度是 在创建数组实例时建立。这些值不能 在实例的生命周期内发生变化。 https://msdn.microsoft.com/en-us/library/9b9dty7d.aspx

为什么必须首先实现 IList?

IList的定义:表示一个非泛型的对象集合 可以通过索引单独访问。

https://msdn.microsoft.com/en-us/library/system.collections.ilist.aspx

Array 是通过索引访问的,而 IList 容纳了这个索引,这就是 Array 实现 IList 的原因。

供参考:Why array implements IList?

【讨论】:

【解决方案2】:

是的,如果System.Array 实现了IReadOnlyList 或类似的接口,它似乎应该是一个更好的设计。但是,IReadOnlyList<T> 出现在 .Net 4.5 中,而 System.Array 保留在最初的 .Net 1.0 中。微软,恕我直言,尽了最大的努力并隐藏 Add 通过显式接口实现

http://referencesource.microsoft.com/#mscorlib/system/array.cs,156e066ecc4ccedf

  ...
int IList.Add(Object value)
{
    throw new NotSupportedException(Environment.GetResourceString("NotSupported_FixedSizeCollection"));
} 
  ...

所以你不能这样做

int[] myArr = { 1, 2 };

myArr.Add(3);

但你可以坚持使用Add(并得到NotSupportedException)通过

((IList) myArr).Add(3);

甚至

if (!myArr.IsFixedSize) {
  // we have very strange array, let's try adding a value to it
  ((IList) myArr).Add(3);
}

【讨论】:

    【解决方案3】:

    它确实提供了 Add,但是通过抛出 NotSupportedException(参见 MSDN),因为数组的大小是固定的。

    你得到一个编译错误的原因,相反,是因为接口是显式实现的,所以如果你想调用你需要转换为IList的方法。请参阅有关 explicit interface implementation 的 C# 指南。

    【讨论】:

      【解决方案4】:

      虽然实现接口的类必须实现接口的所有成员,但它可以显式地实现它们:

      public class MyList<T> : IList<T>
      {
          // ... shortened for simplicity
          void ICollection<T>.Add(T item) {  } // explicit implementation
      }
      

      如果您以这种方式实现该方法,它将在MyList&lt;T&gt; 的实例上不可见:

      MyList<int> list = new MyList<int>();
      list.Add(5); // would NOT compile
      ((IList<int>)list).Add(5); // can be compiled
      

      因此,如果您有int[],您可以这样做:

      int[] array = new int[0];
      ((IList<int>)array).Add(5);
      

      它会编译,但在运行时会抛出NotSupportedException,因为数组有固定大小,你不能添加一个新元素到数组,因为它的大小是在初始化时确定 (new int[0])。

      【讨论】:

      • Add() 不是ICollection 的一部分
      • @haim770 是的:reference source
      • 你是对的。我提到了非通用版本,它是由Array (明确)实现的
      【解决方案5】:

      System.Array 类实现 IList 但不提供 Add()

      当然它是通过显式实现来实现的(没有办法实现接口而不实现某些成员)。

      为什么数组实现IList

      嗯,主要是表明它支持索引器。

      但实际上数组实现了有效的IList 用法之一。 IList 接口有一个名为IsFixedSize 的属性,根据文档

      获取一个值,该值指示 IList 是否具有固定大小。

      然后

      固定大小的集合在集合创建后不允许添加或删除元素,但允许修改现有元素。

      所以数组实现返回IsFixedSize = true 并在AddInsertRemoveRemoveAt 方法中抛出NotSupportedException

      【讨论】:

      • 谢谢!这更接近我需要的答案。我还没有接受答案,因为我想知道为什么 IList 首先被放在那里!可能有另一个接口(例如 IArray),它可能只对 IList 的 Array 成员有用 - 例如IsFixedSize、IsReadOnly、IndexOf()-
      • 你是对的。 AFAIC BCL 设计师考虑了这些替代方案并决定走这条路。通用IList&lt;T&gt; 也一样,它也有这样的缺点。从 .NET 4.5 开始,IReadOnlyList&lt;T&gt; 最接近数组是什么(但它缺少索引器设置器)。
      【解决方案6】:

      根据msdn:

      IList.Add(对象)

      调用此方法总是会引发 NotSupportedException异常。

      Array Class - 见显式接口实现部分

      Array 有这个方法。要调用此方法,您应该显式转换为IList。这个方法不能调用,因为数组是固定大小的,这个大小不能动态改变。

      【讨论】:

        【解决方案7】:

        IList 在三个不同的类别中实现:

        • 只读
        • 大小可变
        • 固定大小

        显然Array 类型是IList 的固定大小实现。 无法从Array 访问Add() 方法的原因是该方法是显式实现的:

        public class A : IList {
            public void IList.Add(object o){
                 ...
            }
        }
        

        这意味着您需要先将数组转换为 IList,然后才能使用 Add 方法(即使它会引发不受支持的异常)。

        你可能会说这是一个糟糕的设计,很多人会同意你的观点。

        阅读更多关于明确定义的接口: https://msdn.microsoft.com/en-us/library/aa288461(v=vs.71).aspx

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-01-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-08-23
          • 2010-11-12
          • 2011-04-04
          相关资源
          最近更新 更多