【问题标题】:What interfaces do all arrays implement in C#?所有数组在 C# 中都实现了哪些接口?
【发布时间】:2010-12-19 10:39:11
【问题描述】:

作为一个新的 .NET 3.5 程序员,我开始学习 LINQ,我发现了一些我以前没有注意到的非常基本的东西:

这本书声称每个数组都实现了IEnumerable<T>(显然,否则我们不能使用 LINQ 来处理数组上的对象......)。当我看到这个时,我想我从来没有真正考虑过这个,我问自己所有数组还实现了什么——所以我检查了 System.Array 使用对象浏览器(因为它是 CLR 中每个数组的基类),令我惊讶的是,它没有实现 IEnumerable<T>

所以我的问题是:定义在哪里?我的意思是,我怎样才能准确地知道每个数组实现了哪些接口?

【问题讨论】:

    标签: c# .net arrays interface-implementation


    【解决方案1】:

    来自documentation(强调我的):

    [...] Array 类实现了System.Collections.Generic.IList<T>System.Collections.Generic.ICollection<T>System.Collections.Generic.IEnumerable<T> 通用接口。 这些实现在运行时提供给数组,因此对文档构建工具不可见。

    编辑:正如 Jb Evain 在他的评论中指出的那样,只有向量(一维数组)实现了通用接口。至于为什么多维数组不实现泛型接口,我不太确定,因为它们确实实现了非泛型对应物(参见下面的类声明)。

    System.Array 类(即每个数组)也实现了这些非泛型接口:

    public abstract class Array : ICloneable, IList, ICollection, IEnumerable, IStructuralComparable, IStructuralEquatable
    

    【讨论】:

    • 我想说:继承了这个非泛型类,从而实现了这些非泛型接口
    • 我讨厌问愚蠢的问题,然后我真的想先在 MSDN 上找到我的答案。这次我错过了...抱歉给您带来麻烦并感谢您的帮助。
    • 我没有投反对票,但只有向量(一维数组)类型实现了通用接口。多维数组类型不实现它们。
    • @Jb Evain:好点子!还值得注意的是锯齿状数组。
    • @Hosam Aly:锯齿状数组只不过是恰好包含其他向量的向量。所以这里没有惊喜。
    【解决方案2】:

    您可以使用小代码 sn-p 凭经验找到问题的答案:

    foreach (var type in (new int[0]).GetType().GetInterfaces())
        Console.WriteLine(type);
    

    运行上面的 sn-p 会产生以下输出(.NET 4.0):

    System.ICloneable
    System.Collections.IList
    System.Collections.ICollection
    System.Collections.IEnumerable
    System.Collections.IStructuralComparable
    System.Collections.IStructuralEquatable
    System.Collections.Generic.IList`1[System.Int32]
    System.Collections.Generic.ICollection`1[System.Int32]
    System.Collections.Generic.IEnumerable`1[System.Int32]
    

    `1 表示<T>

    .NET 4.5.NET Standard 1.0 及更高版本)之后,多了两个接口:

    System.Collections.Generic.IReadOnlyList`1[System.Int32]
    System.Collections.Generic.IReadOnlyCollection`1[System.Int32]
    

    【讨论】:

    • +1,虽然我会使用 typeof(int[]) 而不是 (new int[0].GetType()...
    • 我喜欢这个。还支持来自 MSDN 文档的引用(将其与迭代 typeof(Array).GetType().GetInterfaces() 的输出进行比较,其中缺少通用实现)。
    • @Thomas:感谢您的建议。正如@BoltClock 所述,我更喜欢使用(new int[0]).GetType() 来确保结果包括任何在运行时提供给数组的实现
    • 请注意,在 .NET 4.5(.NET Standard 1.0)中,他们引入了另外两个,IReadOnlyList 和 IReadOnlyCollection。
    【解决方案3】:

    .NET 4.5 开始, 数组还实现了接口System.Collections.Generic.IReadOnlyList<T>System.Collections.Generic.IReadOnlyCollection<T>

    因此,在使用 .NET 4.5 时,由数组实现的接口的完整列表变为(使用Hosam Aly's answer 中提供的方法获得):

    System.Collections.IList
    System.Collections.ICollection
    System.Collections.IEnumerable
    System.Collections.IStructuralComparable
    System.Collections.IStructuralEquatable
    System.Collections.Generic.IList`1[System.Int32]
    System.Collections.Generic.ICollection`1[System.Int32]
    System.Collections.Generic.IEnumerable`1[System.Int32]
    System.Collections.Generic.IReadOnlyList`1[System.Int32]
    System.Collections.Generic.IReadOnlyCollection`1[System.Int32]
    

    奇怪的是,好像忘记更新documentation on MSDN来提这两个接口了。

    【讨论】:

    • 您链接的 documentation 包含此信息,但有点隐藏:“从 .NET Framework 2.0 开始,Array 类实现了 System.Collections.Generic.IList<T>System.Collections.Generic.ICollection<T>System.Collections.Generic.IEnumerable<T> 泛型接口。在运行时将实现提供给数组,因此,泛型接口不会出现在 Array 类的声明语法中。"
    【解决方案4】:

    仔细研究数组接口,他们可能会实现它们,但实际上他们并没有真正做到这一点……看看下面的代码:

                var x = new int[] { 1, 2, 3, 4, 5 };
            var y = x as IList<int>;
            Console.WriteLine("The IList:" + string.Join(",", y));
            try
            {
                y.RemoveAt(1);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
            Console.WriteLine(string.Join(",", y));
    

    它产生以下输出: result

    所以解析有效,但并非所有内容都受支持,这从固定长度集合的角度来看是正确的,但如果你真的相信它是一个列表,那就大错特错了。 SOLID 中的 Liskov 原则 :(.

    对于快速测试this 会有所帮助。

    【讨论】:

    • 亮点。我可以看到微软的观点,一个数组有一个“计数”,并且是可索引的。但你是对的,它不能实现 RemoveAt(x) 因为这意味着重新确定数组的尺寸。我想这是可能的,因为 CLR 可以移动对变量的引用。 - 如果没有它,里氏替换确实是不可能的。我想的解决方案是将 IList 分解为 IFixedList 和 IFlexibleList,并让 Array 仅实现 IFixedList。不过,在大多数情况下,我认为铸造是一种便利。
    • 实际上 IList 接口也有一个通过 ICollection 称为 IsReadOnly 的属性。因此,如果 IsReadOnly 返回为 true,则不需要 IList 实现来实际处理操作集合的调用,这是针对数组的。
    【解决方案5】:

    我在Array的SZArrayHelper嵌套类中找到了IList&lt;T&gt;, ICollection&lt;T&gt;, IEnumerable&lt;T&gt;的实现。

    但我必须警告你 - 你会发现更多问题......

    The refference

    在那之后我只有一个 - there_is_no_array ;)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-12-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多