foreach with SqlDataReader?

Oli*_*ver 12 c#

我有以下代码:

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

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

SqlDataReader reader = getAddressQuery.sqlReader;
while (reader.Read())
{
    someText.InnerText = reader[0].ToString();
}
Run Code Online (Sandbox Code Playgroud)

哪个有效.

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

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

Joe*_*Joe 24

像下面这样的东西.请注意,IDataReader派生自IDataRecord哪个公开用于处理当前行的成员:

IEnumerable<IDataRecord> GetFromReader(IDataReader reader)
{
    while(reader.Read()) yield return reader;
}

foreach(IDataRecord record in GetFromReader(reader))
{
    ... process it ...
}
Run Code Online (Sandbox Code Playgroud)

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

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();
Run Code Online (Sandbox Code Playgroud)

更新以回应Caleb Bell的评论.

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

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

public static IEnumerable<IDataRecord> Enumerate(this IDataReader reader)
{
    while (reader.Read())
    {
        yield return reader;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

reader.Enumerate.Select(r => GetMyTypeFromRecord(r))
Run Code Online (Sandbox Code Playgroud)


Ada*_*rth 12

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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