[英].net core - combine a list of func with or to a single func
Hello i try to generate a single Func from a list combined by or. 您好,我尝试从由或组合而成的列表中生成单个Func。
var funcs = new List<Func<User, bool>>()
{
(u) => u.Id.Equals(entityToFind.Id),
(u) => u.UserName == entityToFind.UserName,
(u) => u.Email == entityToFind.Email
};
//TODO: Some magic that funs is euqaly to that:
Func<User, bool> func = (u) => u.Id.Equals(entityToFind.Id) || u.UserName == entityToFind.UserName || u.Email == entityToFind.Email;
I also tried it with Expressions, like that: 我也用Expressions尝试过,就像这样:
private Dictionary<string, Expression<Func<User, bool>>> private Dictionary<string, Expression<Func<User, bool>>> test(User entityToFind)
{
return new Dictionary<string, Expression<Func<User, bool>>>() {
{"Id", (u) => u.Id.Equals(entityToFind.Id) },
{"Name", (u) => u.UserName == entityToFind.UserName },
{"Email", (u) => u.Email == entityToFind.Email }
};
}
public static Expression<Func<T, bool>> ToOrExpression<T>(this Dictionary<string, Expression<Func<T, bool>>> dict)
{
var expressions = dict.Values.ToList();
if (!expressions.Any())
{
return t => true;
}
var delegateType = typeof(Func<T, bool>)
.GetGenericTypeDefinition()
.MakeGenericType(new[]
{
typeof(T),
typeof(bool)
}
);
var tfd = Expression.OrElse(expressions[0], expressions[1]);
var combined = expressions
.Cast<Expression>()
.Aggregate( (e1, e2) => Expression.OrElse(e1, e2) );
return (Expression<Func<T, bool>>)Expression.Lambda(delegateType, combined);
}
test(entityToFind).ToOrExpression();
But there i will get the following error: 但是我会得到以下错误:
The binary operator OrElse is not defined for the types 'System.Func 2[Models.User,System.Boolean]' and 'System.Func
2[Models.User,System.Boolean]' 没有为类型'System.Func
2[Models.User,System.Boolean]' and 'System.Func
2 [Models.User,System.Boolean]'定义二进制运算符OrElse。
While you could create a wrapper method to combine a bunch of Func
s, because you are using Entity Framework, that would cause the entire dataset to be downloaded into memory and the search done locally. 尽管您可以创建包装器方法来组合一堆
Func
,因为您使用的是Entity Framework,但这将导致将整个数据集下载到内存中并在本地进行搜索。 What you should be using is Expression<Func<T, bool>>
instead. 您应该使用的是
Expression<Func<T, bool>>
。
Fortunately Marc Gravell has already written a handy bit of code to combine expressions . 幸运的是, 马克·格雷夫(Marc Gravell ) 已经编写了一些方便的代码来组合表达式 。 Your question is strictly a dupliucate because you want to combine more than 2 together, but that is quite easy with a little Linq.
您的问题严格是重复的,因为您要将两个以上的组合在一起,但是使用少量的Linq相当容易。 So, lets start with your expressions first, the code barely changes:
因此,让我们先从表达式开始,代码几乎没有变化:
var expressions = new List<Expression<Func<User, bool>>>()
{
(u) => u.Id.Equals(entityToFind.Id),
(u) => u.UserName == entityToFind.UserName,
(u) => u.Email == entityToFind.Email
};
Now using Marc's code and modifying it to be or
instead of and
: 现在使用Marc的代码并将其修改为
or
代替and
:
public static class ExpressionExtensions
{
public static Expression<Func<T, bool>> OrElse<T>(
this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
var parameter = Expression.Parameter(typeof(T));
var leftVisitor = new ReplaceExpressionVisitor(expr1.Parameters[0], parameter);
var left = leftVisitor.Visit(expr1.Body);
var rightVisitor = new ReplaceExpressionVisitor(expr2.Parameters[0], parameter);
var right = rightVisitor.Visit(expr2.Body);
return Expression.Lambda<Func<T, bool>>(
Expression.OrElse(left, right), parameter);
}
private class ReplaceExpressionVisitor
: ExpressionVisitor
{
private readonly Expression _oldValue;
private readonly Expression _newValue;
public ReplaceExpressionVisitor(Expression oldValue, Expression newValue)
{
_oldValue = oldValue;
_newValue = newValue;
}
public override Expression Visit(Expression node)
{
if (node == _oldValue)
return _newValue;
return base.Visit(node);
}
}
}
No you combine your expressions with the Linq Aggregate
method: 不,您可以将表达式与Linq
Aggregate
方法结合使用:
var combinedExpression = expressions.Aggregate((x, y) => x.OrElse(y));
And use it something like this: 并使用像这样的东西:
var result = db.Things.Where(combinedExpression);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.