У меня есть сомнение, когда-то я сделал это преобразование из DataTable
кому: List<T>
:
List<EDog> lstDogs = (from drRow in dsDogs.Tables[0].AsEnumerable()
select new EDog()
{
intIdDog = drRow.Field<int>("IdDog"),
intIdOwner = drRow.Field<int?>("IdOwner"),
intAge = drRow.Field<int>("Age"),
strName = drRow.Field<string>("Name")
}).ToList();
Это хорошо работало, но теперь я думаю о выполнении его универсальный, так, чтобы любой тип DataSet мог быть преобразован в список со строгим контролем типов.
Как я мог сделать это универсальным? возможно, делегат, окружающий эту часть и создающий объект?
new EDog()
{
intIdDog = drRow.Field<int>("IdDog"),
intIdOwner = drRow.Field<int?>("IdOwner"),
intAge = drRow.Field<int>("Age"),
strName = drRow.Field<string>("Name")
}
Я попробовал его, но получите ошибку:
select (lambda) expected....
Какое-либо предложение?
Причина, почему мне нужно это, состоит в том, потому что каждый DataRow результата, должен быть преобразован в Объект для лучшего управления.
Являются чем-то вроде этого, что вы ищете?
public static List<T> ConvertDS<T>(DataSet ds, Converter<DataRow, T> converter)
{
return
(from row in ds.Tables[0].AsEnumerable()
select converter(row)).ToList();
}
Хорошо, давайте немного повеселимся:
public static class DataTableExtensions
{
public static List<T> ToGenericList<T>(this DataTable datatable, Func<DataRow, T> converter)
{
return (from row in datatable.AsEnumerable()
select converter(row)).ToList();
}
}
class EDog
{
private int intIdDog;
private int intIdOwner;
private int intAge;
private string strName;
...
public static EDog Converter(DataRow row)
{
return new EDog
{
intIdDog = (int)row["IdDog"],
intIdOwner = (int)row["IdOwner"],
intAge = (int)row["Age"],
strName = row["Name"] as string
};
}
}
Использование:
List<EDog> dogs = dsDogs.Tables[0].ToGenericList<EDog>(EDog.Converter);
Но здесь недостаточно развлечений, верно? Как насчет этого:
class DataRowKeyAttribute : Attribute
{
private readonly string _Key;
public string Key
{
get { return _Key; }
}
public DataRowKeyAttribute(string key)
{
_Key = key;
}
}
static class DataTableExtensions
{
public static List<T> ToGenericList<T>(this DataTable datatable) where T : new()
{
return (from row in datatable.AsEnumerable()
select Convert<T>(row)).ToList();
}
private static T Convert<T>(DataRow row) where T : new()
{
var result = new T();
var type = result.GetType();
foreach (var fieldInfo in type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance))
{
var dataRowKeyAttribute = fieldInfo.GetCustomAttributes(typeof (DataRowKeyAttribute), true).FirstOrDefault() as DataRowKeyAttribute;
if (dataRowKeyAttribute != null)
{
fieldInfo.SetValue(result, row[dataRowKeyAttribute.Key]);
}
}
return result;
}
}
class EDog
{
[DataRowKey("IdDog")]
private int intIdDog;
[DataRowKey("IdOwner")]
private int intIdOwner;
[DataRowKey("Age")]
private int intAge;
[DataRowKey("Name")]
private string strName;
...
}
Использование:
List<EDog> dogs = dsDogs.Tables[0].ToGenericList<EDog>();
И если вы хотите НАСТОЯЩИЙ развлечься, добавьте обработку ошибок, рассмотрите возможность кэширования данных отражения для повышения производительности и изменения полей на свойства.
Он не поддается легкому преобразованию, вы можете это сделать но, вероятно, это не сэкономит много работы.
Подумайте о внутренних знаниях в вашем примере кода: вы знаете тип и имя каждого столбца в DataTable
, а также тип и имя свойства, которому он сопоставляется в типе вывода. Альтернативой было бы знать тип и индекс каждого столбца (подставляя имя для индекса). В обоих случаях вам нужно будет определить отображение, которое будет содержать эту информацию.
Альтернативой может быть создание преобразователя на основе соглашений - другими словами, имена столбцов DataTable
и их целевые свойства должны быть названы согласованно, а отклонение от этого соглашения приведет к сбою преобразования. .