【问题标题】:ExpressionTree to Negate a String OperationExpressionTree 否定字符串操作
【发布时间】:2015-12-03 16:20:53
【问题描述】:

我有一个将 lambda 添加到 IQueryable 的通用方法。下面的添加了一个 StartsWith lambda。我现在要做的是创建一个 NotStartsWith lambda。由于 NotStartsWith 不是字符串运算符,我不知道从哪里开始。

我认为(应该)有一种方法可以构建一个处理否定操作的 EpressionTree。但看起来它们都适用于 Type 上的当前方法调用,所以我的下一个想法是做一个 IndexOf 并测试!= 0。

由于我确定我需要处理其他运算符的解决方案,我希望找到一种方法来创建一个 lambda,我可以在其中进行方法调用并将结果与​​另一个常量进行比较,即(字符串) .Substring(3,7) == "abcd"。我只是想不出在 ExpressionTree 中进行比较的方法。

这就是我为 StartsWith 所拥有的,它工作正常。我只需要一种方法来否定它,或者(对于未来的操作甚至更好)找到一种通过比较来构建表达式的方法。

    static IQueryable<T> ETForStartsWith<T>(IQueryable<T> query, string propertyValue, PropertyInfo propertyInfo)
    {
        ParameterExpression e = Expression.Parameter(typeof(T), "e");
        MemberExpression m = Expression.MakeMemberAccess(e, propertyInfo);
        ConstantExpression c = Expression.Constant(propertyValue, typeof(string));
        MethodInfo mi = typeof(string).GetMethod("StartsWith", new Type[] { typeof(string) });
        Expression call = Expression.Call(m, mi, c);

        Expression<Func<T, bool>> lambda = Expression.Lambda<Func<T, bool>>(call, e);
        return query.Where(lambda);
    }

感谢您的帮助!

【问题讨论】:

    标签: c# lambda expression-trees


    【解决方案1】:

    只是negate一个方法调用结果:

        /// <summary>
        /// Adds "Where(_ => !_.StringProperty.StartsWith("someValue"))" to the query.
        /// </summary>
        static IQueryable<T> AddNotStartsWith<T>(IQueryable<T> query, PropertyInfo propertyInfo, string value)
        {
            var parameter = Expression.Parameter(typeof(T));
            var memberAccess = Expression.MakeMemberAccess(parameter, propertyInfo);
            var startsWithMethod = typeof(string).GetMethod("StartsWith", new[] { typeof(string) });
            var methodCall = Expression.Call(memberAccess, startsWithMethod, Expression.Constant(value));
    
            return query
                .Where(Expression.Lambda<Func<T, bool>>(Expression.Not(methodCall), parameter));
        }
    

    或更通用的方式:

        static IQueryable<T> AddComparisonExpression<T>(IQueryable<T> query, PropertyInfo propertyInfo, Func<Expression, Expression> getComparisonExpression)
        {
            var parameter = Expression.Parameter(typeof(T));
            var memberAccess = Expression.MakeMemberAccess(parameter, propertyInfo);
    
            return query
                .Where(Expression.Lambda<Func<T, bool>>(getComparisonExpression(memberAccess), parameter));
        }
    
        /// <summary>
        /// Adds "Where(_ => !_.StringProperty.StartsWith("someValue"))" to the query.
        /// </summary>
        static IQueryable<T> AddNotStartsWith<T>(IQueryable<T> query, PropertyInfo propertyInfo, string value)
        {
            return AddComparisonExpression(query, propertyInfo, memberAccess =>
            {
                var startsWithMethod = typeof(string).GetMethod("StartsWith", new[] { typeof(string) });
                var methodCall = Expression.Call(memberAccess, startsWithMethod, Expression.Constant(value));
    
                return Expression.Not(methodCall);
            });
        }
    
        /// <summary>
        /// Adds "Where(_ => _.StringProperty.Substring(startIndex, length) == value)" to the query.
        /// </summary>
        static IQueryable<T> AddSubstringEquals<T>(IQueryable<T> query, PropertyInfo propertyInfo, int startIndex, int length, string value)
        {
            return AddComparisonExpression(query, propertyInfo, memberAccess =>
            {
                var substringMethod = typeof(string).GetMethod("Substring", new[] { typeof(int), typeof(int) });
                var methodCall = Expression.Call(memberAccess, substringMethod, Expression.Constant(startIndex), Expression.Constant(length));
    
                return Expression.Equal(methodCall, Expression.Constant(value));
            });
        }
    

    【讨论】:

      猜你喜欢
      • 2011-05-12
      • 1970-01-01
      • 1970-01-01
      • 2021-03-23
      • 2013-09-06
      • 2012-06-13
      相关资源
      最近更新 更多