C#lambda查询使用generics类型
我有三个class,他们都有财产日期。 我想写一个generics类来返回一个日期的所有记录。 现在的问题是:如何使用generics类型T编写lambda表达式?
代码简单如下(我不会编译,因为“r.Date”不起作用,但它是我想要实现的效果)
Class GenericService: IGenericService where T:class { ... readonly IGenericRepository _genericRepository; public IEnumerable GetRecordList(DateTime date) { var query=_genericRepository.FindBy(r=>r.Date=date); }
谢谢你的帮助!
此致,Léona
另一种选择是动态构建Expression
。 如果您不想或不能将IDate
接口添加到模型对象,并且如果FindBy
需要Expression
(例如,它转换为IQueryable
,则此function非常有用IQueryable
内部为EntityFramework或类似。
与@ JonB的答案一样,这没有编译时安全性来确保T
具有Date
属性或字段。 它只会在运行时失败。
public IEnumerable 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>(equalityExpression, parameterExpression); var query = _genericRepository.FindBy(lambdaExpression); return query; }
编写一个具有IDate
的接口,所有实体都必须实现IDate
并编写GenericService
如下所示:
public class GenericService: IGenericService where T : class, IDate { readonly IGenericRepository _genericRepository; public IEnumerable 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; } }
另一种解决方案,如果你不能实现一个接口而又不想使用reflection,可以传递如何将日期传递给GenericService:
由财产:
public class GenericService: IGenericService where T : class { public Func DateGetter { get; set; } readonly IGenericRepository _genericRepository; public IEnumerable GetRecordList(DateTime date) { var query=_genericRepository.FindBy(r => DateGetter(r) == date); } }
由构造函数:
public class GenericService: IGenericService where T : class { Func _dateGetter; public GenericService(..., Func dateGetter) { _dateGetter = dateGetter ... } readonly IGenericRepository _genericRepository; public IEnumerable GetRecordList(DateTime date) { var query=_genericRepository.FindBy(r => _dateGetter(r) == date); } }
通过方法本身:
public class GenericService: IGenericService where T : class { readonly IGenericRepository _genericRepository; public IEnumerable GetRecordList(DateTime date, Func dateGetter) { var query=_genericRepository.FindBy(r => dateGetter(r) == date); } }
按类型:
亚当拉尔夫的解决方案激励了我这个(我猜不是最好的,但它仍然有效)
public class GenericService: IGenericService where T : class { public Dictionary> _dateGetter = new Dictionary>() { { typeof(TypeWithDate), x => ((TypeWithDate)x).Date }, { typeof(TypeWithDate2), x => ((TypeWithDate2)x).Date } }; readonly IGenericRepository _genericRepository; public IEnumerable GetRecordList(DateTime date) { var query=_genericRepository.FindBy(r => _dateGetter[typeof(T)](r) = date); }
}
假设对象列表不是很大,那么为3个类写一些通用的东西可能会过度工程化。 吻 。
objects.Where(obj => (obj as Foo)?.DateTime == date || (obj as Bar)?.DateTime == date || (obj as Baz)?.DateTime == date)
我不确定您的FindBy
方法是如何构造的或它返回的是什么,但您可能能够像这样使用dynamic
关键字:
var query=_genericRepository.FindBy(r=>((dynamic)r).Date==date);
如果FindBy
方法返回IEnumerable
,那么您可能必须在return语句中添加.Cast
,否则您可能会得到一种IEnumerable
。
这绝不是类型安全的,如果T
没有Date
属性,您可能会遇到运行时错误。 但这是一个值得考虑的选择。