c# - 表达式树 : iterate through strings and check if they contained in another Expression

标签 c# .net-4.0 expression-trees

我想要一个函数表达式> AnyColumnContains(string[] value) 它遍历表的所有列并根据列检查值数组,仅当每个值都包含在任何列中时才返回 true。

我已经有一个函数可以将每一列与一个值进行匹配,但是我在扩展它以根据每个值检查列时遇到了问题

这是我得到的:

Expression<Func<T, bool>> AnyColumnContains<T>(string value){
    var p = Expression.Parameter(typeof(T), "entity");

    var fieldAccessors = typeof(T)
        .GetProperties(BindingFlags.Instance | BindingFlags.Public)
        .Where(f => f.PropertyType == typeof(string))
        .Select(f => Expression.Property(p, f))
        .ToArray();

    var fieldArray = Expression.NewArrayInit(typeof(string), fieldAccessors);

    var concatCall = Expression.Call(typeof(string).GetMethod(
         "Concat", new[] { typeof(string[]) }), fieldArray);

    var contains = Expression.Call(
        concatCall,
        typeof(string).GetMethod("Contains", new[] { typeof(string) }),
        Expression.Constant(value));

    return Expression.Lambda<Func<T, bool>>(contains, p);
}

我尝试使用自己的扩展方法并将 Contains 替换为它,但问题是我使用 sqlite 并且无法转换表达式,因为提供者不知道这些方法

这就是我想要的:

Expression<Func<T, bool>> AnyColumnContains<T>(string[] values){
    // ... //

    var contains  = // build Expression Tree that matches all values against concatCall and only returns true if all values are contained.

    return Expression.Lambda<Func<T, bool>>(contains, p);
}

最佳答案

与其从头开始创建一个全新的方法,您可以简单地组合您已有的有效方法。

我们可以使用以下方法将谓词组合在一起:

public static class PredicateBuilder
{
    public static Expression<Func<T, bool>> True<T>() { return f => true; }
    public static Expression<Func<T, bool>> False<T>() { return f => false; }

    public static Expression<Func<T, bool>> Or<T>(
        this Expression<Func<T, bool>> expr1,
        Expression<Func<T, bool>> expr2)
    {
        var secondBody = expr2.Body.Replace(expr2.Parameters[0], expr1.Parameters[0]);
        return Expression.Lambda<Func<T, bool>>
              (Expression.OrElse(expr1.Body, secondBody), expr1.Parameters);
    }

    public static Expression<Func<T, bool>> And<T>(
        this Expression<Func<T, bool>> expr1,
        Expression<Func<T, bool>> expr2)
    {
        var secondBody = expr2.Body.Replace(expr2.Parameters[0], expr1.Parameters[0]);
        return Expression.Lambda<Func<T, bool>>
              (Expression.AndAlso(expr1.Body, secondBody), expr1.Parameters);
    }
}

它依赖于以下方法将一个表达式的所有实例替换为另一个表达式:

public static Expression Replace(this Expression expression,
    Expression searchEx, Expression replaceEx)
{
    return new ReplaceVisitor(searchEx, replaceEx).Visit(expression);
}

internal class ReplaceVisitor : ExpressionVisitor
{
    private readonly Expression from, to;
    public ReplaceVisitor(Expression from, Expression to)
    {
        this.from = from;
        this.to = to;
    }
    public override Expression Visit(Expression node)
    {
        return node == from ? to : base.Visit(node);
    }
}

现在我们所要做的就是为每个值调用单值版本的 AnyColumnContainsOr 所有结果:

public static Expression<Func<T, bool>> AnyColumnContains<T>(IEnumerable<string> values)
{
    return values.Select(value => AnyColumnContains<T>(value))
        .Aggregate((a, b) => a.Or(b));
}

关于c# - 表达式树 : iterate through strings and check if they contained in another Expression,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33082267/

相关文章:

javascript - 如何访问此网格的行对象?

.net-4.0 - 从 3.5 升级到 4 时 edmx 文件中的警告

c# - Validation.ErrorTemplate 确实在绑定(bind)到对象属性时触发

c# - 由于 JIT_MethodAccessCheck,编译的表达式树很慢

c# - 可靠地检测 C# 表达式树中编译器生成的类

c# - 应用程序资源的数据绑定(bind)窗口标题

c# - 从 JToken 获取 Parent 的困惑

c# - 与代表的麻烦

c# - DotNetOpenAuth 和 C# 桌面应用程序

c++ - 在 Spirit:Qi 中构建自定义表达式树(没有 Utree 或 Boost::Variant)