C#lambda查询使用泛型类型

时间:2016-05-18 08:39:32

标签: c# generics lambda

我有三个班,他们都有一个属性Date。我想编写一个泛型类来返回一个日期的所有记录。 现在的问题是:如何使用泛型类型T?

编写lambda表达式

代码简单如下(我不会编译,因为“r.Date”不起作用,但它是我想要实现的效果)

Class GenericService<T>: IGenericService<T> where T:class
{
      ...
      readonly IGenericRepository<T> _genericRepository;
      public IEnumerable<T> GetRecordList(DateTime date)
      {
             var query=_genericRepository.FindBy(r=>r.Date=date);
}

谢谢你的帮助!

此致 LEONA

5 个答案:

答案 0 :(得分:14)

编写一个包含IDate的界面,所有实体都必须实现IDate并写下GenericService,如下所示:

public class GenericService<T>: IGenericService<T> where T : class, IDate
{
    readonly IGenericRepository<T> _genericRepository;
    public IEnumerable<T> GetRecordList(DateTime date)
    {
         var query=_genericRepository.FindBy(r => r.Date = date);
    }
}

public interface IDate
{
    DateTime Date{ set; get; }
}

public class Entity : IDate
{
    DateTime Date { set; get; }
}

答案 1 :(得分:6)

如果您无法实现界面并且不想使用反射,那么另一种解决方案可能是传递如何将日期传递给GenericService:

属性:

public class GenericService<T>: IGenericService<T> where T : class
{
    public Func<T, DateTime> DateGetter { get; set; }

    readonly IGenericRepository<T> _genericRepository;
    public IEnumerable<T> GetRecordList(DateTime date)
    {
        var query=_genericRepository.FindBy(r => DateGetter(r) == date);
    }
}

由构造函数:

public class GenericService<T>: IGenericService<T> where T : class
{
    Func<T, DateTime> _dateGetter;

    public GenericService(..., Func<T, DateTime> dateGetter)
    {
        _dateGetter = dateGetter
        ...
    }

    readonly IGenericRepository<T> _genericRepository;
    public IEnumerable<T> GetRecordList(DateTime date)
    {
        var query=_genericRepository.FindBy(r => _dateGetter(r) == date);
    }
}

通过方法本身:

public class GenericService<T>: IGenericService<T> where T : class
{
    readonly IGenericRepository<T> _genericRepository;
    public IEnumerable<T> GetRecordList(DateTime date, Func<T, DateTime> dateGetter)
    {
        var query=_genericRepository.FindBy(r => dateGetter(r) == date);
    }
}

按类型:

Adam Ralph&#39;解决方案激励了我这个(我猜不是最好的,但它仍然有效)

public class GenericService<T>: IGenericService<T> where T : class
{
    public Dictionary<Type, Func<object, DateTime>> _dateGetter = new Dictionary<Type, Func<object, DateTime>>()
    {
        { typeof(TypeWithDate), x => ((TypeWithDate)x).Date },
        { typeof(TypeWithDate2), x => ((TypeWithDate2)x).Date }
    };

    readonly IGenericRepository<T> _genericRepository;
    public IEnumerable<T> GetRecordList(DateTime date)
    {
        var query=_genericRepository.FindBy(r => _dateGetter[typeof(T)](r) = date);
    }

}

答案 2 :(得分:5)

另一种选择是动态构建Expression。如果您不希望或不能将IDate接口添加到模型对象,并且FindBy需要Expression<Func<T, bool>>(例如,它转换为{ {1}}内部用于EntityFramework或类似内容。

与@ JonB的答案一样,这没有编译时安全性,以确保IQueryable<T>.Where(...)具有T属性或字段。它只会在运行时失败。

Date

答案 3 :(得分:3)

假设对象列表不是很大,那么为3个类写一些通用的东西可能会过度工程化。 KISS

objects.Where(obj =>
    (obj as Foo)?.DateTime == date ||
    (obj as Bar)?.DateTime == date ||
    (obj as Baz)?.DateTime == date)

答案 4 :(得分:1)

我不确定您的FindBy方法的结构或返回方式,但您可以使用dynamic关键字,如下所示:

   var query=_genericRepository.FindBy(r=>((dynamic)r).Date==date);

如果FindBy方法返回IEnumerable<T>,那么您可能必须在return语句中添加.Cast<T>(),否则您可能会得到IEnumerable<dynamic>类型的<。 / p>

这绝不是类型安全的,如果T没有Date属性,您可能会遇到运行时错误。但这是一个值得考虑的选择。