C#lambda查询使用泛型类型

Leo*_*ona 13 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);
}
Run Code Online (Sandbox Code Playgroud)

谢谢你的帮助!

此致,Léona

Kah*_*azi 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; }
}
Run Code Online (Sandbox Code Playgroud)

  • 我可以问你为什么要给赏金?你不喜欢自己的(赞成和接受)答案吗?你真正期待什么? (5认同)
  • 您可能希望在`FindBy`方法调用中使用第二个等号(与OP不同).无论是那个或`FindBy`采用`Func <T,DateTime>`并且传入的func将覆盖所有日期类的Date属性并搜索日期! (2认同)

rom*_*aga 7

如果你不能实现一个接口并且不想使用反射,另一个解决方案可能是传递如何获取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);
    }
}
Run Code Online (Sandbox Code Playgroud)

由构造函数:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

通过方法本身:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

按类型:

Adam Ralph的解决方案激发了我的灵感(我猜不是最好的,但它仍然有效)

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);
    }
Run Code Online (Sandbox Code Playgroud)

}


yaa*_*kov 5

另一种选择是Expression动态构建.这可能是有用的,如果你不想或不能添加一个IDate接口连接到模型对象,并且如果FindBy需要的Expression<Func<T, bool>>(例如,将其转换为IQueryable<T>.Where(...)内部进行的EntityFramework或相似.

与@ JonB的答案一样,这没有编译时安全性来确保T具有Date属性或字段.它只会在运行时失败.

public IEnumerable<T> GetRecordList(DateTime date)
{
    var parameterExpression = Expression.Parameter(typeof(T), "object");
    var propertyOrFieldExpression = Expression.PropertyOrField(parameterExpression, "Date");
    var equalityExpression = Expression.Equal(propertyOrFieldExpression, Expression.Constant(date, typeof(DateTime)));
    var lambdaExpression = Expression.Lambda<Func<T, bool>>(equalityExpression, parameterExpression);

    var query = _genericRepository.FindBy(lambdaExpression);
    return query;
}
Run Code Online (Sandbox Code Playgroud)