尝试为linq中的日期创建大于,等于或大于动态过滤器 [英] Trying to create a morethan, equal or greaterthan dynamic filter for dates in linq
问题描述
我一直在尝试为Linq创建一个表达式树过滤器,该过滤器接受2个日期和一串可能的值{"lessthan","equals","morethan"}.我希望将调用的格式设置为Query.Where(CompareDates(x => x.left,right,小于"));
I have been trying to create a expression tree filter for Linq that take 2 dates and a string of possible values { "lessthan", "equals", "morethan" }. I wish to format the call to be something like Query.Where(CompareDates(x => x.left, right, "less than"));
我有代码:
public static IQueryable<TSource> CompareDates<TSource>(
this IQueryable<TSource> source,
Expression<Func<TSource, DateTime?>> left,
DateTime? right,
string equality)
{
if (right == null || string.IsNullOrWhiteSpace(equality))
return source;
var p = left.Parameters.Single();
Expression member = p;
Expression leftExpression = Expression.Property(member, "left");
Expression rightParameter = Expression.Constant(right, typeof(DateTime));
BinaryExpression BExpression = null;
switch (equality)
{
case "lessthan":
BExpression = Expression.LessThan(leftExpression, rightParameter);
break;
case "equal":
BExpression = Expression.Equal(leftExpression, rightParameter);
break;
case "morethan":
BExpression = Expression.GreaterThan(leftExpression, rightParameter);
break;
default:
throw new Exception(String.Format("Equality {0} not recognised.", equality));
}
return source.Where(Expression.Lambda<Func<TSource, bool>>(BExpression, p));
}
不幸的是,它产生错误"System.ArgumentException:在SARRestAPI.Extensions的System.Linq.Expressions.Expression.Property(Expression expression,String propertyName)上没有为类型'Model'定义实例属性'left'. Expressions.CompareDates [TSource](IQueryable 1 source, Expression
1 src,提供了DateTime,字符串相等)"
Unfortunately it is producing an error of "System.ArgumentException: Instance property 'left' is not defined for type 'Model' at System.Linq.Expressions.Expression.Property(Expression expression, String propertyName) at SARRestAPI.Extensions.Expressions.CompareDates[TSource](IQueryable1 source, Expression
1 src, DateTime supplied, String equality)"
任何人都知道为什么会这样吗?
Anyone have an ideas why this is happening?
推荐答案
您要执行的操作是使用传入选择器的.Body
,而不要查找.left
.意思是,给定x => x.Foo.Bar.Blap
的输入选择器,一个常量和一个比较,您想通过复用都使用x
(该参数是已经完成)和身体(x.Foo.Bar.Blap
).
Here we go; what you want to do is use the .Body
of the incoming selector, not look for .left
. Meaning, given an input selector of x => x.Foo.Bar.Blap
, a constant, and a comparison, you want to construct something like x => x.Foo.Bar.Blap < someValue
, by reusing both the x
(the parameter, which you're already doing) and the body (x.Foo.Bar.Blap
).
在代码中(请注意,这适用于任何TValue
,而不仅仅是DateTime
):
In code (note this works for any TValue
, not just DateTime
):
public enum Comparison
{
Equal,
NotEqual,
LessThan,
LessThanOrEqual,
GreaterThan,
GreaterThanOrEqual
}
public static IQueryable<TSource> Compare<TSource, TValue>(
this IQueryable<TSource> source,
Expression<Func<TSource, TValue>> selector,
TValue value,
Comparison comparison)
{
Expression left = selector.Body;
Expression right = Expression.Constant(value, typeof(TValue));
BinaryExpression body;
switch (comparison)
{
case Comparison.LessThan:
body = Expression.LessThan(left, right);
break;
case Comparison.LessThanOrEqual:
body = Expression.LessThanOrEqual(left, right);
break;
case Comparison.Equal:
body = Expression.Equal(left, right);
break;
case Comparison.NotEqual:
body = Expression.NotEqual(left, right);
break;
case Comparison.GreaterThan:
body = Expression.GreaterThan(left, right);
break;
case Comparison.GreaterThanOrEqual:
body = Expression.GreaterThanOrEqual(left, right);
break;
default:
throw new ArgumentOutOfRangeException(nameof(comparison));
}
return source.Where(Expression.Lambda<Func<TSource, bool>>(body, selector.Parameters));
}
示例用法(此处使用LINQ-to-Objects,但它也适用于其他LINQ后端):
Example usage (here using LINQ-to-Objects, but it should work for other LINQ backends, too):
var arr = new[] { new { X = 11 }, new { X = 12 }, new { X = 13 }, new { X = 14 } };
var source = arr.AsQueryable();
var filtered = source.Compare(x => x.X, 12, Comparison.GreaterThan);
foreach (var item in filtered)
{
Console.WriteLine(item.X); // 13 and 14
}
请注意,使用C#vCurrent您可以执行以下操作:
Note that with C# vCurrent you can do:
var body = comparison switch
{
Comparison.LessThan => Expression.LessThan(left, right),
Comparison.LessThanOrEqual => Expression.LessThanOrEqual(left, right),
Comparison.Equal => Expression.Equal(left, right),
Comparison.NotEqual => Expression.NotEqual(left, right),
Comparison.GreaterThan => Expression.GreaterThan(left, right),
Comparison.GreaterThanOrEqual => Expression.GreaterThanOrEqual(left, right),
_ => throw new ArgumentOutOfRangeException(nameof(comparison)),
};
return source.Where(Expression.Lambda<Func<TSource, bool>>(body, selector.Parameters));
您可能会更喜欢.
这篇关于尝试为linq中的日期创建大于,等于或大于动态过滤器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!