所有数组都在C#中实现什么接口?


74

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

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

所以我的问题是:定义在哪里?我的意思是,我该如何确切地知道每个数组实现哪些接口?

Answers:


78

文档(重点是我的):

[...] 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

3
我会说:继承了这个非泛型类,从而实现了这些非泛型接口
abatishchev 2010年

我讨厌问一些愚蠢的问题,然后我真的想首先在MSDN上找到我的答案。这次我错过了它...麻烦您了,谢谢您的帮助。
ET。

5
我没有投票,但是只有向量(一维数组)类型实现了通用接口。多维数组类型不能实现它们。
伊万

@Jb Evain:好点!还值得注意的是,锯齿状数组确实可以做到。
Hosam Aly 2010年

3
@Hosam Aly:锯齿状数组不过是恰巧包含其他向量的向量。因此,这里不足为奇。
伊布

68

您可以使用一个小的代码段凭经验找到问题的答案:

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

运行上面的代码片段将导致以下输出(on .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]

11
+1,尽管我会使用typeof(int[])而不是(new int[0].GetType()...
Thomas Levesque 2010年

1
我喜欢这个。还支持MSDN文档中的报价(将其与迭代通过的输出进行比较typeof(Array).GetType().GetInterfaces(),缺少通用实现)。
BoltClock

16
@托马斯:谢谢你的建议。我更喜欢用来(new int[0]).GetType()确保结果包括运行时提供给数组的所有实现,如@BoltClock所述。
Hosam Aly 2010年

请注意,在.NET 4.5(.NET Standard 1.0)中,他们又引入了两个,即IReadOnlyList和IReadOnlyCollection。

55

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

因此,当使用.NET 4.5时,由数组实现的接口的完整列表将变为(使用Hosam Aly的答案中介绍的方法获得):

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]

奇怪的是,似乎忘记了更新MSDN上的文档以提及这两个接口。


1
你的链接文件包含此信息,但有点隐蔽:“与.NET Framework 2.0,起始Array类实现System.Collections.Generic.IList<T>System.Collections.Generic.ICollection<T>System.Collections.Generic.IEnumerable<T>。泛型接口的实现提供了在运行时数组,其结果是,通用的接口做不会出现在Array类的声明语法中。”
蒂姆·施密特

1

仔细地在数组接口上,它们可以实现它们,但实际上它们并没有真正做到这一点。

            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 :(。

对于快速测试,将有所帮助。


辉煌的点。我可以看到Microsoft的观点,即数组具有“ Count”并且可索引。但是您是对的,它不能实现RemoveAt(x),因为那将意味着重新定义数组的尺寸。我想这是可能的,因为CLR可以移动对变量的引用。-而且,没有它,Liskov替代的确不在窗外。我猜想的解决方案是将IList分解为IFixedList和IFlexibleList,并使Array仅实现IFixedList。不过,在大多数情况下,我仍认为强制转换是一种方便。
西蒙·米勒

实际上,IList <T>接口还通过ICollection <T>具有称为IsReadOnly的属性。因此,如果IsReadOnly返回为true(对于Array),则不需要IList <T>实现来实际处理操纵集合的调用。
卡斯珀·科塔尔

0

我发现的实施IList<T>, ICollection<T>, IEnumerable<T>SZArrayHelper在Array嵌套类中。

但是我必须警告您-在那里您会发现更多问题...

引用

之后,我只有一个-there_is_no_array;)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.