Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/280.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# foreach循环中的浇铸_C# - Fatal编程技术网

C# foreach循环中的浇铸

C# foreach循环中的浇铸,c#,C#,我遇到了以下代码: foreach (var row in datatable.Rows.Cast<DataRow>()) { some code here } foreach(datatable.Rows.Cast()中的变量行) { 这里有一些代码 } 现在,我认为在foreach循环中进行强制转换是不正确的,因为我认为每次循环时都会进行强制转换。但是,我可能错了,也许编译器足够聪明 另一个相关的注意事项是:我怎样才能自己解决这样的问题呢?扩展方法IEnumerable.

我遇到了以下代码:

foreach (var row in datatable.Rows.Cast<DataRow>())
{
  some code here
}
foreach(datatable.Rows.Cast()中的变量行)
{
这里有一些代码
}
现在,我认为在foreach循环中进行强制转换是不正确的,因为我认为每次循环时都会进行强制转换。但是,我可能错了,也许编译器足够聪明

另一个相关的注意事项是:我怎样才能自己解决这样的问题呢?

扩展方法
IEnumerable.Cast
返回一个延迟计算的枚举。这意味着,每当您向它请求“下一个”项时,它都会从底层数据源(本例中的datatable)检索该项,并将其强制转换为指定的类型。因此,在一个
foreach
中进行浇铸并不是不正确的,因为浇铸不是“太多”,而是在必要时对每个项目进行浇铸。添加一个
.ToList()
并不是更好的选择,因为这个Garantues可以强制转换每一个项目,即使您不需要这样做,例如,如果您以
中断退出循环

您可以通过阅读和阅读有关该方法的文章来了解这一点。

它调用
Cast
一次,但实际上会在获取每个项目时对其进行强制转换。因此,每次迭代都有一个cast(至少可能;
cast
在知道没有必要时有一个优化),但只有一个方法调用。
Cast
返回的迭代器将从源(
datatable.Rows
此处)中(惰性地)提取项,并根据循环的请求对每个项进行强制转换

有关更多信息,请参阅我的

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

foreach (var item in complicatedExpression)
{
    ...
}
相当于:

var items = complicatedExpression;
foreach (var item in items)
{
    ...
}
编译器将生成一次调用
GetEnumerator()
的代码,然后使用该代码的结果对集合进行迭代

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

foreach (DataRow row in datatable.Rows)
{
  some code here
}
当编译器隐式地从迭代器中获取每个项时,它将对每个项执行强制转换。这有点鬼鬼祟祟,因为它没有明显的铸造

至于如何判断发生了什么,您可以始终使用
ildasm
查看IL。这可能很有启发性,但有些费时。

如果您有:

foreach(SomeType name in {expression})
{
    // your code
}
{expression}
只计算一次,因此在您的示例中,
Cast()
只调用一次。然后对
{expression}
的结果进行枚举处理,结果如下(取决于许多情况,例如
{expression}
的结果支持什么API):


为了自己找到答案,你可以下载一些反编译器并检查实际的源代码。我最喜欢的是JetBrains(Re#的制造商)。还有一个非常普遍的例子,我实际上认为我必须将强制转换从循环中移出,放在它前面。最后一个隐藏强制转换示例非常重要,因为我一直假设foreach循环中的var是经过类型检查的,直到我遇到一个bug,触发了循环上的
InvalidCastException
using(var iter = {expression}.GetEnumerator())
{
    while(iter.MoveNext()
    {
        SomeType name = iter.Current; // location on recent compilers
        // your code
    }
}