为什么C#多维数组不实现IEnumerable<;T>;?

为什么C#多维数组不实现IEnumerable<;T>;?,c#,.net,arrays,multidimensional-array,C#,.net,Arrays,Multidimensional Array,我刚刚注意到C#中的多维数组没有实现IEnumerable,而它实现了IEnumerable。对于一维数组,实现了IEnumerable和IEnumerable 为什么会有这种差异?如果多维数组是IEnumerable,那么它肯定也应该实现通用版本?我注意到这一点是因为我试图在多维数组上使用扩展方法,除非使用Cast或类似方法,否则将失败;因此,我可以明确地看到让多维数组实现IEnumerable的一个参数 为了澄清我在代码中的问题,我希望下面的代码打印四次true,而实际上它打印true,fa

我刚刚注意到C#中的多维数组没有实现
IEnumerable
,而它实现了
IEnumerable
。对于一维数组,实现了
IEnumerable
IEnumerable

为什么会有这种差异?如果多维数组是
IEnumerable
,那么它肯定也应该实现通用版本?我注意到这一点是因为我试图在多维数组上使用扩展方法,除非使用
Cast
或类似方法,否则将失败;因此,我可以明确地看到让多维数组实现
IEnumerable
的一个参数

为了澄清我在代码中的问题,我希望下面的代码打印四次
true
,而实际上它打印
true
false
true
true

int[] singleDimensionArray = new int[10];
int[,] multiDimensional = new int[10, 10];

Debug.WriteLine(singleDimensionArray is IEnumerable<int>);
Debug.WriteLine(multiDimensional is IEnumerable<int>);
Debug.WriteLine(singleDimensionArray is IEnumerable);
Debug.WriteLine(multiDimensional is IEnumerable);
int[]singleDimensionArray=newint[10];
int[,]多维=新的int[10,10];
WriteLine(singleDimensionArray是IEnumerable);
WriteLine(多维是IEnumerable);
WriteLine(singleDimensionArray是IEnumerable);
WriteLine(多维是IEnumerable);

交错数组也不支持
IEnumerable
,因为多维结构实际上不是一个类型的数组,而是一个类型数组的数组:

int[] singleDimensionArray = new int[10];
int[][] multiJagged = new int[10][];

Debug.WriteLine(singleDimensionArray is IEnumerable<int>);
Debug.WriteLine(multiJagged is IEnumerable<int[]>);
Debug.WriteLine(singleDimensionArray is IEnumerable);
Debug.WriteLine(multiJagged is IEnumerable);
int[]singleDimensionArray=newint[10];
int[][]多锯齿=新int[10][];
WriteLine(singleDimensionArray是IEnumerable);
WriteLine(multiJagged是IEnumerable);
WriteLine(singleDimensionArray是IEnumerable);
WriteLine(multiJagged是IEnumerable);
打印真的,真的,真的,真的


注意
int[,]
不是一个
IEnumerable
,这是由于另一个答案中指定的原因,即没有通用的方法知道要迭代哪个维度。对于交错数组,没有太多的解释空间,因为语法非常清楚它是一个数组数组。

CLR有两种不同类型的数组:保证为一维且下限为0的向量,以及更一般的数组,可以具有非零边界和非0的秩

根据CLI规范第8.9.1节:

此外,创建的向量具有 元素类型T,实现 接口
System.Collections.Generic.IList
(§8.7),其中U:=T

我得说我觉得这很奇怪。考虑到它已经实现了
IEnumerable
,我不明白为什么它不应该实现
IEnumerable
。实现
IList
没有多大意义,但是简单的通用接口就可以了


如果需要,可以调用
Cast
(如果使用的是.NET 3.5),或者编写自己的方法来迭代数组。为了避免强制转换,您必须编写自己的方法,找到每个维度的上下限,并以这种方式获取内容。不太令人愉快。

有一个解决方法:您可以将任何多维数组转换为IEnumerable

public static class ArrayExtensions
{
    public static IEnumerable<T> ToEnumerable<T>(this Array target)
    {
        foreach (var item in target)
            yield return (T)item;
    }
}
公共静态类ArrayExtensions
{
公共静态IEnumerable-ToEnumerable(此数组目标)
{
foreach(目标中的var项目)
收益回报(T)项;
}
}

逆向思考。二维数组已存在。列举一下。创建一个二维数组,其中包含初始数组或标记的分数和位置,包括重复值

int[] secondmarks = {20, 15, 31, 34, 35, 50, 40, 90, 99, 100, 20};

IEnumerable<int> finallist = secondmarks.OrderByDescending(c => c);

int[,] orderedMarks = new int[2, finallist.Count()];

Enumerable.Range(0, finallist.Count()).ToList().ForEach(k => {orderedMarks[0, k] = (int) finallist.Skip(k).Take(1).Average();
orderedMarks[1, k] = k + 1;}); 

Enumerable.Range(0, finallist.Count()).Select(m => new {Score = orderedMarks[0, m], Place = orderedMarks[1, m]}).Dump();

零边界一维数组同时实现
IEnumerable
IEnumerable
,但遗憾的是,多维数组只实现
IEnumerable
。@Jader Dias的“变通方法”确实将多维数组转换为
IEnumerable
,但代价巨大:数组中的每个元素都将被装箱

以下是一个不会对每个元素都进行装箱的版本:

public static class ArrayExtensions
{
    public static IEnumerable<T> ToEnumerable<T>(this T[,] target)
    {
        foreach (var item in target)
            yield return item;
    }
}
公共静态类ArrayExtensions
{
公共静态IEnumerable到numerable(此T[,]目标)
{
foreach(目标中的var项目)
收益回报项目;
}
}

递归没有在讨论中。@recursive:干杯,修正了。只是混淆了我的术语。他没有谈论锯齿数组,他谈论的是多维数组。很棒的东西!但是我必须明确指定泛型类型,因此用法变成:myArray.ToEnumerable(),这与
IEnumerable.Cast
@Markus Brilliant相同,这应该是公认的答案。另一方面,如果数组可以包含空值,它将成为Matrix.Cast(Of T)。其中(函数(x)x不是空的)@smirkingman,或者它通过
IEnumerator
访问数组,这会导致装箱,正如@SergeyTeplyakov在回答中所说的那样。如果数组是显式类型(
t[,]
t[,]
,等等),装箱就不会发生。此外,C语言规范(版本4.0)在第6.1.6段中只提到将一维数组转换为
IList
及其基本接口。但遗憾的是,
T[,]
不是
ICollection
。同样难看的是:
multiDimensional
隐式转换为非泛型类型
System.Collections.IList
(因为
System.Array
实现了该接口)。因此可以说
System.Collections.IList mdCast=多维。然后在
mdCast
上使用单参数索引器只会在运行时失败。看见注意异常类型,
ArgumentException
。真难看。
public static class ArrayExtensions
{
    public static IEnumerable<T> ToEnumerable<T>(this T[,] target)
    {
        foreach (var item in target)
            yield return item;
    }
}