使用通用方法从数据表加载List <T>

时间:2019-09-15 14:13:46

标签: c#

我用数据表加载了10个不同的List 。 该数据表是从Sqlite数据库加载的。 为此,我将相同的方法重复10次。 这是我的代码示例:

//List to be load
public static List<AircraftModel> Aircraft = new List<AircraftModel>();
public static List<AirlineModel> Airline = new List<AirlineModel>();

//Method to load the list Aircraft with the datatable
public void LoadAircraft(DataTable data)
    {
       foreach (DataRow row in data.Rows)
        {
          Aircraft.Add(new AircraftModel
            {
                Id = Int32.Parse(row["id"].ToString()),
                Registration = row["registration"].ToString(),
                Capacity = Int32.Parse(row["capacity"].ToString()),
                Type = row["type"].ToString()
            });
        }
    }

//Method to load the List Airline with datatable
public void LoadAirline(DataTable data)
    {
        foreach (DataRow row in data.Rows)
        {
            Airline.Add(new AirlineModel
            {
                Code = row["code"].ToString(),
                AirlineName = row["name"].ToString()
            });
        }
    }

是否可以使用这样的通用方法来优化我的代码:

//call method to load the List
 GetData<AircraftModel>(Aircraft, datatable);
 GetData<AirlineModel>(Airline, datatable);

//Unique generic method to load the 10 List < T >
public void GetData<T>(List< T > ListToBeLoad, DataTable table)
       where T : class, new()
    {

        foreach (DataRow row in table.Rows)
        {
            ListToBeLoad.Add( new T
            {
              ......
              HELP NEEDED PLEASE
              ......
            }
        }            
    }

提前感谢您的答复和主张

西里尔

2 个答案:

答案 0 :(得分:3)

您有两种方法,可以创建一个映射方法并将其作为参数传递,也可以使用AutoMapper。

这里是第一种解决方案的2个示例(没有AutoMapper)

填充到现有列表的示例

PopulateList(list, dataTable, (row) =>
    new AircraftModel
    {
        Id = int.Parse(row["id"].ToString()),
        Registration = row["registration"].ToString(),
        Capacity = int.Parse(row["capacity"].ToString()),
        Type = row["type"].ToString()

    }
);

public static void PopulateList<T>(List<T> list, DataTable data, Func<DataRow, T> mapFunc)
    where T : new()
{
    foreach (DataRow row in data.Rows)
    {
        list.Add(mapFunc(row));
    }
}

创建新列表并映射行的示例。

var list2 = Map(dataTable, (row) =>
    new AircraftModel
    {
        Id = int.Parse(row["id"].ToString()),
        Registration = row["registration"].ToString(),
        Capacity = int.Parse(row["capacity"].ToString()),
        Type = row["type"].ToString()

    }
);

public static IEnumerable<T> Map<T>(DataTable data, Func<DataRow, T> mapFunc)
    where T : new()
{
    foreach (DataRow row in data.Rows)
    {
        yield return mapFunc(row);
    }
}

答案 1 :(得分:1)

您可能已经注意到,问题在于您需要了解列以获取正确的数据,并需要了解属性以将其存储在正确的位置。因此,您的代码需要了解每个单独的类-很好:您将不会摆脱此代码。

通常,当您要构造某些东西时,您可能会想到一个工厂,即能够构造特定类型实例的方法(或类)。在您的情况下,工厂 class 可能如下所示:

public abstract class Factory<T>
{
    public T Create(DataRow row);
}

现在,您要做的下一步就是为您要创建的每种类型创建特定的实例,例如

public sealed class AirlineModelFactory : Factory<AirlineModel>
{
    public override AirlineModel Create(DataRow row)
    {
        return new AirlineModel
        {
            Code = row["code"].ToString(),
            AirlineName = row["name"].ToString()
        };
    }
}

现在样板代码是这样的:

public void GetData<T>(List<T> list, DataTable table, Factory<T> factory)
where T : class, new()
{
    foreach (DataRow row in table.Rows)
    {
        list.Add(factory.Create(row));
    }            
}

,您可以称其为

GetData(AirlineList, table, new AirlineModelFactory());
GetData(AirpoirtList, table, new AirportModelFactory());
// etc.

尽管有争议,但是您可能希望保留工厂实例(甚至注入它们以进行控制反转)以避免new。 但是,您将注意到,仍然需要为N类型创建N类/方法。

要使事情自动化更多,您可以在工厂中引入“通用”基类,例如

public abstract class GenericFactory
{
    public abstract object CreateObject(DataRow row);
}

然后实施

public abstract class Factory<T> : GenericFactory
{
    public override object CreateObject(DataRow row) => Create(row);
    // ...
}

有了这个,您可以想到一个查询字典Dictionary<Type, GenericFactory>。通过选择正确的类型,然后转换为正确的T,您将获得正确的实例。但是,这是一种服务定位器模式-一种代码气味,因为缺少字典中的注册会在运行时导致错误-但根据您的需要,它仍然可能会有所帮助。