foreach with SqlDataReader?

时间:2011-08-18 10:52:33

标签: c#

我有以下代码:

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循环不像更高级语言那样灵活吗?

3 个答案:

答案 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"]);
          }
    }
}