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