我似乎无法调和这两个观察结果:
T[,]
) 无法分配给 IEnumerable<T>
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>());
,但这会增加一个额外的迭代器,而且我正在寻找性能。迭代器可能不会显着影响性能,但感觉必须有更好的方法。
我认为 foreach 只是使用
(在这种情况下IEnumerable<T>.GetEnumerator()
是var
)或T
(在这种情况下IEnumerable.GetEnumerator()
是var
)的语法糖。object
事实并非如此 - 语言规范基本上有处理数组和
IEnumerable<>
的特定规则。回到 C# 1,我们根本没有泛型,因此要让 foreach
在数组上工作,had 是特定的规则。
有关更多详细信息,请参阅语言规范 - 例如,C# 7 规范中的第 13.9.5 节。