我有以下代码:
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循环不像更高级语言那样灵活吗?
答案 0 :(得分:24)
如下所示。请注意IDataReader
派生自IDataRecord
,它公开了用于处理当前行的成员:
IEnumerable<IDataRecord> GetFromReader(IDataReader reader)
{
while(reader.Read()) yield return reader;
}
foreach(IDataRecord record in GetFromReader(reader))
{
... process it ...
}
或者甚至类似下面这样的内容,以获取读者的强类型实体对象的枚举或列表:
IEnumerable<T> GetFromReader<T>(IDataReader reader, Func<IDataRecord, T> processRecord)
{
while(reader.Read()) yield return processRecord(reader);
}
MyType GetMyTypeFromRecord(IDataRecord record)
{
MyType myType = new MyType();
myType.SomeProperty = record[0];
...
return myType;
}
IList<MyType> myResult = GetFromReader(reader, GetMyTypeFromRecord).ToList();
更新以回应Caleb Bell的评论。
我同意Enumerate
是一个更好的名字。
事实上,在我个人的“普通”图书馆中,我现在用IDataReader
上的扩展方法替换了上面的内容:
public static IEnumerable<IDataRecord> Enumerate(this IDataReader reader)
{
while (reader.Read())
{
yield return reader;
}
}
调用者可以使用以下方法获取强类型对象:
reader.Enumerate.Select(r => GetMyTypeFromRecord(r))
答案 1 :(得分:11)
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循环的可比性使用实际上并不具有可比性。
答案 2 :(得分:1)
你也可以这样做......
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<DbDataRecord>()){
Console.Write("{0} {1} ({2}) - ", (string)c["Name"], (string)c["Surname"], (string)c["Mail"]);
Console.WriteLine((string)c["LoginID"]);
}
}
}