将数据读取器中的行转换为键入的结果

Ant*_*ony 27 c# datareader list

我正在使用第三方库来返回数据阅读器.我想要一个简单的方法,并尽可能通用将其转换为对象列表.
例如,假设我有一个具有2个属性EmployeeId和Name的类'Employee',我希望将数据读取器(包含员工列表)转换为List <Employee>.
我想我别无选择,只能迭代数据阅读器的各行,并为每一行将它们转换为我将添加到List的Employee对象.更好的解决方案?我正在使用C#3.5,理想情况下我希望它尽可能通用,以便它适用于任何类(DataReader中的字段名称与各种对象的属性名称匹配).

Joe*_*orn 62

你真的需要一个清单,还是IEnumerable足够好?

我知道你希望它是通用的,但更常见的模式是在目标对象类型上有一个接受数据行(或IDataRecord)的静态Factory方法.这看起来像这样:

public class Employee
{
    public int Id { get; set; }
    public string Name { get; set; }

    public static Employee Create(IDataRecord record)
    {
        return new Employee
        {
           Id = record["id"],
           Name = record["name"]
        };
    }
}
Run Code Online (Sandbox Code Playgroud)

.

public IEnumerable<Employee> GetEmployees()
{
    using (var reader = YourLibraryFunction())
    {
       while (reader.Read())
       {
           yield return Employee.Create(reader);
       }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,如果你真的需要一个列表而不是IEnumerable,你可以调用.ToList()结果.我想你也可以使用泛型+委托来使这个模式的代码更易于重用.

更新: 我今天再次看到这一点,感觉就像编写通用代码:

public IEnumerable<T> GetData<T>(IDataReader reader, Func<IDataRecord, T> BuildObject)
{
    try
    {
        while (reader.Read())
        {
            yield return BuildObject(reader);
        }
    }
    finally
    {
         reader.Dispose();
    }
}

//call it like this:
var result = GetData(YourLibraryFunction(), Employee.Create);
Run Code Online (Sandbox Code Playgroud)


Meh*_*ari 24

您可以构建一个扩展方法,如:

public static List<T> ReadList<T>(this IDataReader reader, 
                                  Func<IDataRecord, T> generator) {
     var list = new List<T>();
     while (reader.Read())
         list.Add(generator(reader));
     return list;
}
Run Code Online (Sandbox Code Playgroud)

并使用它像:

var employeeList = reader.ReadList(x => new Employee {
                                               Name = x.GetString(0),
                                               Age = x.GetInt32(1)
                                        });
Run Code Online (Sandbox Code Playgroud)

乔尔的建议很好.你可以选择退货IEnumerable<T>.转换上面的代码很容易:

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

如果要将列自动映射到属性,则代码构思是相同的.您可以使用通过读取匹配列来使用反射generator查询typeof(T)和设置对象属性的函数替换上面代码中的函数.但是,我个人更喜欢定义一个工厂方法(就像Joel的答案中提到的那样)并将它的委托传递给这个函数:

 var list = dataReader.GetEnumerator(Employee.Create).ToList();
Run Code Online (Sandbox Code Playgroud)