当 foreach 没有实现 IEnumerable<T> 时,它如何知道 2D 数组的项类型?

问题描述 投票:0回答:1

我似乎无法调和这两个观察结果:

  1. 二维数组 (
    T[,]
    ) 无法分配给
    IEnumerable<T>
  2. 类型的变量
  3. foreach(var item in (T[,])array2d)
    中,编译器知道
    var
    T

我认为

foreach
只是使用
IEnumerable<T>.GetEnumerator()
(在这种情况下
var
T
)或
IEnumerable.GetEnumerator()
(在这种情况下
var
object
)的语法糖。

这是导致我提出这个问题的场景。我有一个需要

IEnumerable<Foo>
的方法。

int Average(IEnumerable<Foo> values)
{
    // lots of code
    foreach (var foo in values)
    {
        var bar = foo.GetBar();
        // lots of code
    }
    // lots of code
    return result;
}

Foo[] array1d = /**/;
Average(array1d);

然后我想将一个 2D 数组传递给这个方法,但它无法编译;错误是

CS1503 Argument 1: cannot convert from 'Foo[*,*]' to 'System.Collections.Generic.IEnumerable<Foo>'

Foo[,] array2d = /**/;
Average(array2d);

但是,我发现如果我只是添加这个重载,它确实可以编译。当我将鼠标悬停在

var foo
上时,编译器知道它是
Foo
,并且能够找到
Foo.GetBar()

void Average(Foo[,] values)
{
    // lots of code
    foreach (var foo in values)
    {
        var bar = foo.GetBar();
        // lots of code
    }
    // lots of code
    return result;
}

不幸的是,这重复了我的代码。我也可以调用

Average(array2d.Cast<Foo>());
,但这会增加一个额外的迭代器,而且我正在寻找性能。迭代器可能不会显着影响性能,但感觉必须有更好的方法。

c# multidimensional-array foreach var c#-12.0
1个回答
0
投票

我认为 foreach 只是使用

IEnumerable<T>.GetEnumerator()
(在这种情况下
var
T
)或
IEnumerable.GetEnumerator()
(在这种情况下
var
object
)的语法糖。

事实并非如此 - 语言规范基本上有处理数组和

IEnumerable<>
的特定规则。回到 C# 1,我们根本没有泛型,因此要让
foreach
在数组上工作,had 是特定的规则。

有关更多详细信息,请参阅语言规范 - 例如,C# 7 规范中的第 13.9.5 节。

© www.soinside.com 2019 - 2024. All rights reserved.