为什么我不能做foreach(DataTable.Rows中的var Item)?

时间:2010-02-24 12:06:40

标签: c# .net datatable foreach datarow

我有什么理由不能做到以下几点:

foreach (var Item in DataTable.Rows) {

而不是必须做

foreach (DataRow Item in DataTable.Rows) {

我原以为这是可能的,就像在其他数据类型上一样。例如:

foreach (var Employee in Staff) { // string[] Staff etc...

当我尝试第一个foreach循环时,我得到错误 CS0021:无法将带有[]的索引应用于'object'类型的表达式

为什么编译器不能确定.Rows返回DataRows的集合?

3 个答案:

答案 0 :(得分:28)

Rows有效地返回IEnumerableDataRowCollection),因此编译器只能选择object作为var的类型。如果您要使用Rows.Cast<DataRow>,请使用var

CastEnumerable上定义,因此您必须包含System.Linq。

答案 1 :(得分:23)

Brian对此的理由绝对正确,但有一种更简单的方法可以避免它:使用DataTableExtensions.AsEnumerable()

foreach (var row in DataTable.AsEnumerable())
{
    ...
}

答案 2 :(得分:0)

为什么编译器无法弄清楚.Rows返回了DataRows的集合?

由于数据表行(DataRowCollection)的工作方式是枚举,并且部分与foreach的工作方式有关,并且都与它有多古老。

首先介绍foreach

foreach并不是真的。它更像是while循环的语言快捷方式,该循环获取对象上的枚举数并反复调用MoveNextMoveNextMoveNext ...直到MoveNext返回false,在它停止循环的那一点。 while循环主体所做的第一件事是在枚举器上调用Current,并将响应加载到您在foreach声明中指定的变量中。在第一位之后,将您编写的循环的主体放入while循环的主体中。在您看来,foreach是一个真实的循环。实际上,这就像编译器的查找/替换练习。 C#中的许多事情都是这种方式-新功能和语法减少只是使用旧方法查找/替换代码的方式。

要使foreach类不必实现任何接口或任何特定类型,它只需要具有一个称为GetEnumerator()的方法即可返回”枚举”。

“可以枚举的事物” 被定义为“具有bool MoveNext()方法和返回任何类型对象的Current属性的类”。同样,此“可以枚举的东西” 不必实现任何接口或任何特定类型;它只需要具有一种方法和一种具有特定名称和特定签名的属性。整个过程就像魔术,并且在任何地方都没有约束:

public class ForeachableThing{
  public EnumeratorSchmenumerator GetEnumerator(){
    return new EnumeratorSchmenumerator();
  }
}

public class EnumeratorSchmenumerator{
  public DateTime Current {
    get{ return DateTime.Now; }
  }
  public bool MoveNext() {
    return DateTime.Now.Hour == 0;
  }
}

您可以将这几百万次遍历,以获取当前时间,从午夜到凌晨1点。枚举不需要收集或移动到任何地方。它只需要按要求返回值,并在被告知移动时返回true或false。如果您认为“但一定要实现IEnumerable ..这肯定意味着必须在其中某处键入一些内容。”,我对此进行了概述。否-自从发明了数据表以来,就有可能纯粹基于是否有某种方法/属性来枚举事物


跳至DataTable.Rows;这是一个集合; DataRowCollection准确地说。它确实是从继承自IEnumerable的事实来实现InternalDataCollectionBase接口的,而IEnumerable实现了GetEnumerator()-但它本身只是一个声明“该类必须具有{ {1}}方法返回一个IEnumerator“,而IEnumerator是一个强制执行“必须具有返回Currentobject的{​​{1}}属性的接口返回MoveNext()”。

不一定要实现bool这些接口,但这会有所帮助。

..然后您可能会发现它:实现foreach要求IEnumerator属性是Current

这是编译器错误:

object

'EnumeratorSchmenumerator'未实现接口成员'IEnumerator.Current'。 [现有]'EnumeratorSchmenumerator.Current'无法实现'IEnumerator.Current',因为它没有匹配的返回类型'object'

因此,在选择使用public class EnumeratorSchmenumerator : IEnumerator //look! new bit! { public DateTime Current { get{ return DateTime.Now; } } public bool MoveNext() { return DateTime.Now.Hour == 0; } } 实现DataRowCollection时,他们被迫编写了一个IEnumerable方法,该方法返回了.GetEnumerator(),进而迫使{{ 1}}成为IEnumerator

该对象内部有一个Current,但是编译器不知道,因此它将object键入为DataRow

当您说var时,C#在幕后编写以扩展object的代码将包括对foreach(DataRow r in dt.Rows)的强制转换。

使用foreach表单,就像您写了DataRow