简体   繁体   English

.net core-将一个func列表与单个func组合在一起

[英].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.

相关问题 使用自定义 FUNC 过滤列表 - Filter a list with a custom FUNC 组合表达式(Expression <Func<TIn,TOut> &gt; 带有表情<Func<TOut, bool> &gt;) - Combine Expression (Expression<Func<TIn,TOut>> with Expression<Func<TOut, bool>>) 如何合并多个表达式 <Func<T, bool> &gt;转换为单个表达式以针对DbContext执行? - How to combine multiple Expression<Func<T, bool>> into a single expression to execute against DbContext? 使用单个Func <T,bool> with Where()和继承 - Using a single Func<T,bool> with Where() and inheritance 带列表的表达式功能 <T> .Select()。Contains() - Expression Func with List<T>.Select().Contains() 如何结合表情 <Func<MyClass,bool> &gt; []? - how do I combine Expression<Func<MyClass,bool>>[]? asp.net mvc转换表达式 <Func<TModel, TProperty> &gt;表达 <Func<TModel, bool> &gt; - asp.net mvc convert Expression<Func<TModel, TProperty>> to Expression<Func<TModel, bool>> EF Core:嵌套集合的过滤条件(Func&lt;&gt;)作为变量 - EF Core: filter condition for nested collection (Func<>) as a variable 组合两个表达式 (Expression <Func<T, bool> &gt;) 在一个 - Combining two expressions (Expression<Func<T, bool>>) in a single one 如何使用Func &lt;&gt;修改lambda的单个条件 - How could I use Func<> to modify a single condition of a lambda
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM