需要帮助在C#中使用泛型简化方法

时间:2016-04-28 12:39:20

标签: c# generics

我有下面这样的函数,它使用LinqToSql加载数据库表,并返回转换为我的自定义模型类的条目列表:

    public List<AreaModel> LoadListOfAreaModels(Boolean includeDeleted = false)
    {
        using (LinqToSqlDataContext dc = new LinqToSqlDataContext())
        {
            IQueryable<Areas> filtered = includeDeleted
                ? dc.Areas.Where((c) => !c.DataRowDeleted)
                : dc.Areas;
            return filtered.Select((c) => AreaModel.ModelFactoryFromLinq(c)).ToList();
        }
    }

现在我有很多表,所有表都必须以相同的方式加载和转换。

我可以以某种方式避免输入此功能十几次,只需将AreaModelAreas更改为例如TownModelTowns使用通用函数?

我已经尝试了这个,但失败了,因为如果我只有它的泛型类型参数,我就找不到调用静态类方法的方法。

更多信息:所有XxxModel类都有公共超类ModelBase(不包含我需要调用的静态工厂方法!),所有Linq表类(如AreasTowns)实现公共接口ILinqClass

关于如何以最优雅的方式实现这一点的任何想法?

knittl 的回答启发,我提出了这个解决方案:

    public List<TModel> LoadListOfModels<TLinq, TModel>(
        Func<TLinq, bool> filter,
        Func<TLinq, TModel> modelFactory
        )
        where TLinq : class, ILinqClass
        where TModel : ModelBase
    {
        using (LinqToSqlDataContext dc = new LinqToSqlDataContext())
        {
            return dc.GetTable<TLinq>()
                .Where(filter)
                .Select(modelFactory)
                .ToList();
        }
    }

3 个答案:

答案 0 :(得分:2)

你应该能够传递delegates / Funcs:

public List<TModel> LoadListOfModels<TDbModel, TModel>(
  Func<LinqToSqlDataContext, TDbModel> modelSelector,
  Func<TDbModel, bool> isDeleted,
  Func<TDbModel, TModel> modelFactory,
  bool includeDeleted = false)
{
    using (LinqToSqlDataContext dc = new LinqToSqlDataContext())
    {
        var models = modelSelector(dc);
        var filtered = includeDeleted
            ? models.Where(c => !isDeleted(c))
            : models;

        return filtered.Select(modelFactory).ToList();
    }
}

Area电话如下:

 LoadListOfModels(
   dc => dc.Areas,
   c => c.DataRowDeleted,
   Area.ModelFactoryFromLinq,
   includeDeleted);

Town

 LoadListOfModels(
   dc => dc.Towns,
   c => c.DataRowDeleted,
   Town.ModelFactoryFromLinq,
   includeDeleted);

您甚至可以摆脱includeDeleted参数。只需传递一个过滤器函数Func<TDbModel, bool> filter

return modelsSelector(dc)
  .Where(filter)
  .Select(modelFactory)
  .ToList();

呼叫:

LoadListOfModels(dc => dc.Areas, c => true, Area.ModelFactoryFromLinq);
LoadListOfModels(dc => dc.Areas, c => !c.DataRowDeleted, Area.ModelFactoryFromLinq);

答案 1 :(得分:1)

尝试这种方法:

public abstract class BaseClass<TModel> where TModel : class
{
    public bool DataRowDeleted { get; set; }
    public abstract TModel ModelFactoryFromLinq();
}

public class Area : BaseClass<AreaModel>
{
    public override AreaModel ModelFactoryFromLinq()
    {
        return new AreaModel();
    }
}

public static List<TModel> LoadListOfAreaModels<TContext, TModel>(bool includeDeleted = false)
    where TContext : BaseClass<TModel>, new()
    where TModel : class
{
    using (var dc = new LinqToSqlDataContext())
    {
        IQueryable<TContext> filtered = includeDeleted
            ? dc.GetTable<TContext>().Where((c) => !c.DataRowDeleted)
            : dc.GetTable<TContext>();
        return filtered.Select((c) => c.ModelFactoryFromLinq()).ToList();
    }
}

<强>实现:

List<AreaModel> result = SomeClassName.LoadListOfAreaModels<Area, AreaModel>();

答案 2 :(得分:0)

如果在DataRowDeleted中定义了ModelBase,您应该可以:

public static IQueryable<TModel> LoadListOfQuery<T, TModel>(IQueryable<T> source, Expression<Func<T, TModel>> selector, bool includeDeleted = false) where T : ModelBase {
    IQueryable<T> filtered = includeDeleted ? source : source.Where(s => !s.DataRowDeleted);
    return filtered.Select(selector);
}

然后添加一个函数来评估给定上下文的查询:

public static List<T> ExecList(Func<LinqToSqlDataContext, IQueryable<T>> qf)
{
    using(var c = new LinqToSqlDataContext())
    {
         var q = qf(c);
         return q.ToList();
    }
}

然后你可以这样做:

public List<AreaModel> LoadListOfAreaModels(bool includeDeleted = false)
{
    ExecList(c => LoadListOfQuery(c.Areas, a => AreaModel.ModelFactoryFromLinq(a), includeDeleted);
}