表达式树:遍历字符串并检查它们是否包含在另一个表达式中

本文关键字:表达式 是否 包含 另一个 检查 遍历 字符 字符串 串并 | 更新日期: 2023-09-27 18:17:13

我想要一个函数表达式> 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);
}

我试图使用自己的扩展方法并替换包含它,但问题是,我使用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);
    }
}

现在我们所要做的就是对每个值调用AnyColumnContains的单值版本,并将Or的所有结果一起调用:

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