我有什么理由不能做到以下几点:
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的集合?
答案 0 :(得分:28)
Rows
有效地返回IEnumerable
(DataRowCollection
),因此编译器只能选择object
作为var
的类型。如果您要使用Rows.Cast<DataRow>
,请使用var
。
Cast
在Enumerable上定义,因此您必须包含System.Linq。
答案 1 :(得分:23)
Brian对此的理由绝对正确,但有一种更简单的方法可以避免它:使用DataTableExtensions.AsEnumerable():
foreach (var row in DataTable.AsEnumerable())
{
...
}
答案 2 :(得分:0)
为什么编译器无法弄清楚.Rows返回了DataRows的集合?
由于数据表行(DataRowCollection)的工作方式是枚举,并且部分与foreach
的工作方式有关,并且都与它有多古老。
首先介绍foreach
:
foreach
并不是真的。它更像是while循环的语言快捷方式,该循环获取对象上的枚举数并反复调用MoveNext
,MoveNext
,MoveNext
...直到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
是一个强制执行“必须具有返回Current
和object
的{{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