foreach with SqlDataReader?

我有以下代码:

SqlDataReader reader = getAddressQuery.sqlReader; while (reader.Read()) { foreach (Object ob in reader) { someText.InnerText = someText.InnerText + " " + ob.ToString(); } } 

foreach循环中的代码不会执行。 但是,我可以这样做:

 SqlDataReader reader = getAddressQuery.sqlReader; while (reader.Read()) { someText.InnerText = reader[0].ToString(); } 

哪个有效。

显然我可以使用常规for循环而不是foreach循环来实现相同的结果,但我认为foreach语法更清晰,所以我尽可能使用它。

这里出了什么问题? c#中的foreach循环不像更高级语言那样灵活吗?

像下面这样的东西。 请注意, IDataReader派生自IDataRecord ,它暴露用于处理当前行的成员:

 IEnumerable GetFromReader(IDataReader reader) { while(reader.Read()) yield return reader; } foreach(IDataRecord record in GetFromReader(reader)) { ... process it ... } 

或者甚至类似以下内容,从读者获取强类型实体对象的枚举或列表:

 IEnumerable GetFromReader(IDataReader reader, Func processRecord) { while(reader.Read()) yield return processRecord(reader); } MyType GetMyTypeFromRecord(IDataRecord record) { MyType myType = new MyType(); myType.SomeProperty = record[0]; ... return myType; } IList myResult = GetFromReader(reader, GetMyTypeFromRecord).ToList(); 

更新以回应Caleb Bell的评论。

我同意Enumerate是一个更好的名字。

事实上,在我个人的“通用”库中,我现在用IDataReader上的扩展方法替换了上面的内容:

 public static IEnumerable Enumerate(this IDataReader reader) { while (reader.Read()) { yield return reader; } } 

调用者可以使用以下方法获取强类型对象:

 reader.Enumerate.Select(r => GetMyTypeFromRecord(r)) 

foreach公开了一个IDataRecord ,它将你放入一个非常类似于while循环的船:

 using (SqlConnection conn = new SqlConnection("")) using (SqlCommand comm = new SqlCommand("select * from somewhere", conn)) { conn.Open(); using (var r = comm.ExecuteReader()) { foreach (DbDataRecord s in r) { string val = s.GetString(0); } } } 

如果你想看到更有用的东西,你需要拥有一些自己的代码,将记录中的值提取为更自定义的东西,正如另一个答案所暗示的那样。

无论哪种方式,你都需要自定义代码,无论你是否内联,或者使用while循环,取决于我想要写的频率,不止一次,你应该把它放在一个帮助方法中某处。

并回答一些问题:问题不在于foreach ,而是你试图使用它为你返回的东西,因为你对while循环的可比性使用实际上并不具有可比性。

你也可以这样做……

 string sql = "select * from Users"; using (SqlConnection conn = GetConnection()){ conn.Open(); using (SqlDataReader rdr = new SqlCommand(sql, conn).ExecuteReader()){ foreach (DbDataRecord c in rdr.Cast()){ Console.Write("{0} {1} ({2}) - ", (string)c["Name"], (string)c["Surname"], (string)c["Mail"]); Console.WriteLine((string)c["LoginID"]); } } }