C# 使用SqlDataReader的foreach?

C# 使用SqlDataReader的foreach?,c#,C#,我有以下代码: SqlDataReader reader = getAddressQuery.sqlReader; while (reader.Read()) { foreach (Object ob in reader) { someText.InnerText = someText.InnerText + " " + ob.ToString(); } } foreach循环中的代码不执行。但是,我可以这样做: SqlDataReader reader

我有以下代码:

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<IDataRecord> GetFromReader(IDataReader reader)
{
    while(reader.Read()) yield return reader;
}

foreach(IDataRecord record in GetFromReader(reader))
{
    ... process it ...
}
调用方可以使用以下方法获取强类型对象:

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<DbDataRecord>()){
               Console.Write("{0} {1} ({2}) - ", (string)c["Name"], (string)c["Surname"], (string)c["Mail"]);
               Console.WriteLine((string)c["LoginID"]);
          }
    }
}

我懂了。这有点烦人。@Marc搞错了-SqlDataReader确实实现了IEnumerable-是的,但这会枚举当前IDataRecord的列,而不是行。@Joe在SqlDataReader上似乎返回了整个记录。尽管我的答案与另一个答案基本相同,但为了我自己的利益,我会保留它。我从来没有试过在阅读器上使用foreach,我总是在阅读器打开时破门而入。阅读代码,称之为我手指上的肌肉记忆。这就是说,最终的结果是非常相同的,所以我觉得没有必要重新访问旧代码并进行重构以满足OCD:-@BornToCode首先,这只适用于抽象基类DbDataReader,而不是接口IDataReader。其次,它涉及到迭代器的额外分配。第三,什么是可列举的并不明显。第四,当您可以/无法访问元数据时,它允许在行/网格上使用更小的粒度。第五,它对你没有任何帮助,因为你最终访问数据记录的方式和你访问阅读器的方式完全一样。基本上,阅读可以很好地工作。如果你更喜欢foreach:那也没关系。我不确定,但我假设foreach是迭代记录集中的每个字段,而不是每个记录……GetFromReader方法很好而且优雅,很遗憾框架中没有这样的东西!我创建了一个扩展方法版本,并将其命名为Enumerate。@CalebBell-我同意Enumerate是一个更好的名称,请参阅更新。
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);
        }
    }
}
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"]);
          }
    }
}