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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/275073/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 21:08:42  来源:igfitidea点击:

Why do C# multidimensional arrays not implement IEnumerable<T>?

c#.netarraysmultidimensional-array

提问by driis

I have just noticed that a multidimensional array in C# does not implement IEnumerable<T>, while it does implement IEnumerable. For single-dimensional arrays, both IEnumerable<T>and IEnumerableare implemented.

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

Why this difference? If a multi-dimensional array is IEnumerable, surely it should also implement the generic version? I noticed this because I tried to use an extension method on a multidimensional array, which fails unless you use Cast<T>or similar; so I can definitely see the an argument for making multidimensional arrays implement IEnumerable<T>.

为什么会有这种差异?如果多维数组是IEnumerable,它肯定也应该实现通用版本吗?我注意到这一点是因为我试图在多维数组上使用扩展方法,除非您使用Cast<T>或类似,否则该方法会失败;所以我绝对可以看到使多维数组实现的参数IEnumerable<T>

To clarify my question in code, I would expect the following code to print truefour times, while it actually prints true, false, true, true:

为了在代码中澄清我的问题,我希望以下代码打印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);

采纳答案by Jon Skeet

The CLR has two different kinds of arrays: vectorswhich are guaranteed to be one-dimensional with a lower bound of 0, and more general arrays which can have non-zero bounds and a rank other than 0.

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

From section 8.9.1 of the CLI spec:

来自 CLI 规范的第 8.9.1 节:

Additionally, a created vector with element type T, implements the interface System.Collections.Generic.IList<U>(§8.7), where U := T.

此外,创建的元素类型为 T 的向量实现了接口 System.Collections.Generic.IList<U>(第 8.7 节),其中 U := T。

I have to say it seems pretty weird to me. Given that it already implements IEnumerableI don't see why it shouldn't implement IEnumerable<T>. It wouldn't make as much sense to implement IList<T>, but the simple generic interface would be fine.

我不得不说这对我来说似乎很奇怪。鉴于它已经实现,IEnumerable我不明白为什么它不应该实现IEnumerable<T>。实现 没有多大意义IList<T>,但简单的通用接口就可以了。

If you want this, you could either call Cast<T>(if you're using .NET 3.5) or write your own method to iterate through the array. To avoid casting you'd have to write your own method which found the lower/upper bounds of each dimension, and fetched things that way. Not terribly pleasant.

如果你想要这个,你可以调用Cast<T>(如果你使用 .NET 3.5)或编写你自己的方法来遍历数组。为了避免强制转换,您必须编写自己的方法来找到每个维度的下限/上限,并以这种方式获取内容。不是很愉快。

回答by Konrad Rudolph

Multidimensional arrays are notarrays for the purpose of the inheritance hierarchy. They're a completely separate type. Additionally, this type has no good support from the framework for two possible reasons:

多维数组不是用于继承层次结构的数组。它们是完全独立的类型。此外,由于两个可能的原因,这种类型没有得到框架的良好支持:

  • It's not really that useful. The only real use for multidimensional arrays is matrices. For almost anything else, other data structures (e.g. jagged arrays) are better suited.
  • It's not trivial to devise generic, useful methods for these structures.
  • 它不是那么有用。多维数组唯一真正的用途是矩阵。对于几乎任何其他事物,其他数据结构(例如锯齿状数组)更适合。
  • 为这些结构设计通用的、有用的方法并非易事。

In the case of IEnumerable, how should this have been implemented, i.e. in which order should the elements be enumerated? There's no order inherent in multidimensional arrays.

在 的情况下IEnumerable,这应该如何实现,即应该以何种顺序枚举元素?多维数组没有固有的顺序。

回答by Matthew Scharley

Jagged arrays don't support IEnumerable<int>either, because multidimensional structures aren't really an array of a type, they are an array of an array of a type:

锯齿状数组也不支持IEnumerable<int>,因为多维结构并不是真正的类型数组,它们是类型数组的数组:

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);

Prints true, true, true, true.

打印真,真,真,真。

Note: int[,]isn't an IEnumerable<int[]>, that's for the reasons specified in the other answer, namely there's no generic way to know which dimension to iterate over. With jagged arrays, there isn't as much room for interpretation because the syntax is pretty clear about it being an array of arrays.

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

回答by Jader Dias

There is a workaround: you can convert any multidimensional array to an IEnumerable

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

public static class ArrayExtensions
{
    public static IEnumerable<T> ToEnumerable<T>(this Array target)
    {
        foreach (var item in target)
            yield return (T)item;
    }
}

回答by PEDRO ACOSTA MOLINA

Think inversely. The 2d array already exists. Just enumerate it. Create a 2d array with score and place of an initial array or marks, including duplicate values.

反过来想。二维数组已经存在。列举一下就行了。使用初始数组或标记的分数和位置创建一个二维数组,包括重复值。

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();

Results:

结果:

Score Place

100     1
99      2 
90      3 
50      4 
40      5 
35      6    
34      7    
31      8    
20      9     
20     10 
15     11 

回答by Sergey Teplyakov

Zero bound single dimensional arrays implements both IEnumerableand IEnumerable<T>, but multi-dimensional arrays, unfortunately, implements only IEnumerable. The "workaround" by @Jader Dias indeed converts a multidimensional array to IEnumerable<T>but with a huge cost: every element of an array will be boxed.

零边界单维数组同时实现IEnumerableIEnumerable<T>,但不幸的是,多维数组只实现IEnumerable。@Jader Dias 的“解决方法”确实将多维数组转换为,IEnumerable<T>但成本巨大:数组的每个元素都将被装箱。

Here is a version that won't cause boxing for every element:

这是一个不会对每个元素造成装箱的版本:

public static class ArrayExtensions
{
    public static IEnumerable<T> ToEnumerable<T>(this T[,] target)
    {
        foreach (var item in target)
            yield return item;
    }
}