在 foreach 循环中铸造

use*_*442 1 c#

我遇到了以下代码:

foreach (var row in datatable.Rows.Cast<DataRow>())
{
  some code here
}
Run Code Online (Sandbox Code Playgroud)

现在,我认为在 foreach 循环中进行转换是不正确的,因为我认为它每次循环时都会进行转换。但是,我可能错了,也许编译器足够聪明?

在相关说明中:我怎样才能为自己解决这样的问题?

Jon*_*eet 7

好吧,它调用 Cast<DataRow>一次,但这实际上会在获取每个项目时投射它。因此,有在每次迭代铸造(至少可能;Cast有当它知道这是没有必要的优化),但只有一个方法调用。返回的迭代器Cast将从源(datatable.Rows此处)中(懒惰地)获取项目,并在循环请求时转换每个项目。

有关更多信息,请参阅我的Edulinq 帖子Cast

尽管由于Cast懒惰,这里的水有点混乱,但重要的是要记住,右边的表达式in只计算一次。所以一个循环的形式:

foreach (var item in complicatedExpression)
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

相当于:

var items = complicatedExpression;
foreach (var item in items)
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

编译器将生成调用GetEnumerator() 一次的代码,然后使用其结果迭代集合。

对于这个特定示例,使用的替代方法Cast是让编译器将强制转换放入循环本身:

foreach (DataRow row in datatable.Rows)
{
  some code here
}
Run Code Online (Sandbox Code Playgroud)

编译器将在从迭代器中提取每个项目时隐式地对每个项目执行强制转换。这有点偷偷摸摸,因为它显然不是铸造。

至于你如何知道发生了什么 - 你总是可以ildasm用来查看 IL。这可能很有启发性,但有点费时。