C# 可比较的通用液体
所以我试图创建一个函数,它接受一个IQueryable,并在该IQueryable中包含一个DateTime属性,然后返回一个IQueryable,并与另一个DateTime进行比较 目前,我必须为几个不同的函数执行此操作,并且此代码可能会发生更改,因此我希望此代码能够通用地应用于IQueryable:C# 可比较的通用液体,c#,linq,generics,iqueryable,C#,Linq,Generics,Iqueryable,所以我试图创建一个函数,它接受一个IQueryable,并在该IQueryable中包含一个DateTime属性,然后返回一个IQueryable,并与另一个DateTime进行比较 目前,我必须为几个不同的函数执行此操作,并且此代码可能会发生更改,因此我希望此代码能够通用地应用于IQueryable: FMGQueryableSet = FMGQueryableSet.Where(t => t.Created.Day >= StartDate.Value.Day)
FMGQueryableSet = FMGQueryableSet.Where(t => t.Created.Day >= StartDate.Value.Day)
.Where(t => t.Created.Month >= StartDate.Value.Month)
.Where(t => t.Created.Year >= StartDate.Value.Year);
相反,我希望能够做到这一点:
FMGQueryableSet = SetDateCompare(FMGQueryableSet, t=> t.Created, StartDate, false)
方法存根看起来像这样,但是我不知道如何将传入的属性绑定到IQueryable
public IQueryable<T> SetDateCompare<T>(IQueryable<T> OriginalQuery, Expression<Func<DateTime>> QueryProperty, DateTime ComparisonDate, bool isGreaterThan = true)
where T : class
{
if(isGreaterThan)
{
OriginalQuery = OriginalQuery.Where(QueryProperty >= ComparisonDate.Day)
.Where(QueryProperty >= ComparisonDate.Month)
.Where(QueryProperty >= ComparisonDate.Year);
}
else
{
OriginalQuery = OriginalQuery.Where(QueryProperty <= ComparisonDate.Day)
.Where(QueryProperty <= ComparisonDate.Month)
.Where(QueryProperty <= ComparisonDate.Year);
}
return OriginalQuery;
}
public IQueryable SetDateCompare(IQueryable原始查询、表达式查询属性、日期时间比较数据、布尔值大于等于true)
T:在哪里上课
{
如果(大于)
{
OriginalQuery=OriginalQuery.Where(QueryProperty>=comparisonadate.Day)
.Where(QueryProperty>=comparisonadate.Month)
其中(查询属性>=比较数据年份);
}
其他的
{
OriginalQuery=OriginalQuery.Where(QueryPropertyt=>t.创建了所需调用的一部分,它是一个lambda表达式,表示从类型t获取日期时间的函数,因此此函数的参数应该是Func
考虑到这一点,您应该尝试以下方法:
public IQueryable<T> SetDateCompare<T>(IQueryable<T> OriginalQuery, Func<T,DateTime> getDateFunc, DateTime ComparisonDate, bool isGreaterThan = true)
where T : class
{
if (isGreaterThan)
{
OriginalQuery = OriginalQuery.Where(t => getDateFunc(t).Day >= ComparisonDate.Day)
.Where(t => getDateFunc(t).Month >= ComparisonDate.Month)
.Where(t => getDateFunc(t).Year >= ComparisonDate.Year);
}
else
{
OriginalQuery = OriginalQuery.Where(t => getDateFunc(t).Day <= ComparisonDate.Day)
.Where(t => getDateFunc(t).Month <= ComparisonDate.Month)
.Where(t => getDateFunc(t).Year <= ComparisonDate.Year);
}
return OriginalQuery;
}
public IQueryable SetDateCompare(IQueryable OriginalQuery,Func getDateFunc,DateTime comparisondata,bool isGreaterThan=true)
T:在哪里上课
{
如果(大于)
{
OriginalQuery=OriginalQuery.Where(t=>getDateFunc(t.Day>=comparisonadate.Day)
.Where(t=>getDateFunc(t).Month>=ComparisonDate.Month)
其中(t=>getDateFunc(t).Year>=ComparisonDate.Year);
}
其他的
{
OriginalQuery=OriginalQuery.Where(t=>getDateFunc(t).Day getDateFunc(t).Month getDateFunc(t).Year假设您真的想要显示不寻常的比较逻辑,下面是如何实现的。如果您需要不同的比较逻辑,只需更改表达式ymdCompareLess和YMDComparRegreater
要做的第一件事是创建一个可以传递给where子句的新表达式。您希望能够传递一个表达式,该表达式指示要比较的属性和要在比较中使用的日期值
我在下面为小于比较和大于比较创建了两个表达式。根据为isGreaterThan传入的值,我们为大于比较或小于比较选择表达式
我正在使用我在StackOverflow上第一次看到的替换访问者模式,通过用其他表达式替换所有原始参数来创建一个新的表达式
选择要使用的表达式后,将替换该表达式的参数。第一个参数v1将替换为QueryProperty主体。假设您传递了类似于v=>v.CreatedDate
,则该表达式的主体将是CreatedDate
第二个参数v2将替换为包含传入日期值的表达式常量
结果将是创建的表达式看起来像v=>v.CreatedDate.Day>=(新的日期时间(2005,2,3)).Day
,其中v
是您传入的表达式中的参数
然后我们创建一个lambda表达式,创建的表达式作为主体,传入的参数作为参数
最后,我们使用新的lambda表达式作为过滤器调用.Where方法并返回结果
Expression<Func<DateTime, DateTime, bool>> ymdCompareLess = (v1, v2) => v1.Day <= v2.Day && v1.Month <= v2.Month && v1.Year <= v2.Year;
Expression<Func<DateTime, DateTime, bool>> ymdCompareGreater = (v1, v2) => v1.Day >= v2.Day && v1.Month >= v2.Month && v1.Year >= v2.Year;
public IQueryable<T> SetDateCompare<T>(IQueryable<T> OriginalQuery, Expression<Func<T, DateTime>> QueryProperty, DateTime ComparisonDate, bool isGreaterThan = true)
where T : class
{
LambdaExpression comparisonExpression = isGreaterThan ? ymdCompareGreater : ymdCompareLess;
var replaceVisitor = new ReplaceVisitor(
comparisonExpression.Parameters.ToArray(),
new[] { QueryProperty.Body, Expression.Constant(ComparisonDate) }
);
var whereBody = replaceVisitor.Visit(comparisonExpression.Body);
var whereClause = Expression.Lambda<Func<T, bool>>(whereBody, QueryProperty.Parameters);
return OriginalQuery.Where(whereClause);
}
private class ReplaceVisitor : ExpressionVisitor
{
Expression[] _from;
Expression[] _to;
public ReplaceVisitor(Expression[] from, Expression[] to)
{
this._from = from;
this._to = to;
}
public override Expression Visit(Expression node)
{
var idx = Array.IndexOf(_from, node);
if (idx > -1)
{
return _to[idx];
}
return base.Visit(node);
}
}
表达式YMDComparess=(v1,v2)=>v1.Day=v2.Month&&v1.Year>=v2.Year;
公共IQueryable SetDateCompare(IQueryable原始查询、表达式QueryProperty、日期时间比较数据、布尔值大于等于true)
T:在哪里上课
{
lambdexpression comparisonExpression=大于?Ymdcomparegrater:Ymdcomparess;
var replaceVisitor=新的replaceVisitor(
comparisonExpression.Parameters.ToArray(),
新[]{QueryProperty.Body,Expression.Constant(ComparisonData)}
);
var whereBody=replaceVisitor.Visit(comparisonExpression.Body);
var whereClause=Expression.Lambda(whereBody,QueryProperty.Parameters);
返回原始查询。Where(Where子句);
}
私有类替换访问者:ExpressionVisitor
{
表达式[]来自;
表达[]_至;
公共访问者(表达式[]从,表达式[]到)
{
这个;
这个;
}
公共重写表达式访问(表达式节点)
{
var idx=Array.IndexOf(_from,node);
如果(idx>-1)
{
返回到[idx];
}
返回基地访问(节点);
}
}
谢谢,我现在正在测试它,不过我很确定这应该可以!传入第二个变量最简单的方法是什么,Lamba的明显不工作Ambda应该可以,什么不工作?你在调用中指定了类型了吗?SetDateComparesrry我的intellisense被破坏了。现在可以了哦,我明白了,表达式修复了苏?如果是这样,我会编辑我的回答。他们也检查一下!如果你愿意,这将帮助你扩展linq,我相信你的逻辑中有一个根本性的缺陷。假设创建日期为2014-01-01,起始日期为2013-12-31。第一个位置将过滤掉它,因为1<31。