binaryexpression包含方法

时间:2012-06-29 08:15:22

标签: linq c#-4.0 expression-trees

我创建了一个帮助器类,它能够从字符串参数构建lambda表达式,我可以使用它来过滤查询结果。

但我没有问题,LINQ.Expressions.Expression没有Contains方法。

这是我的代码:

 string member = d.Member;
        object value = d.Value;

        System.Linq.Expressions.Expression expression = System.Linq.Expressions.Expression.Parameter(typeof(T), "e");

        foreach (var property in member.Split('.'))
        {
            expression = System.Linq.Expressions.Expression.PropertyOrField(expression, property);
        }

        ConstantExpression c = System.Linq.Expressions.Expression.Constant(value, typeof(string));

        BinaryExpression b = null;

        switch (d.Operator)
        {
            case FilterOperator.IsEqualTo:

                b = System.Linq.Expressions.Expression.Equal(expression, c);

                break;

            case FilterOperator.Contains:

                b = GetExpression<T>(expression.ToString(), value.ToString()).Body as BinaryExpression;

                break;

            case FilterOperator.IsGreaterThanOrEqualTo:

                b = System.Linq.Expressions.Expression.GreaterThanOrEqual(expression, c);

                break;

            case FilterOperator.IsLessThanOrEqualTo:

                b = System.Linq.Expressions.Expression.LessThanOrEqual(expression, c);

                break;
        }


        CriteriaCollection.Add(b);

static Expression<Func<T, bool>> GetExpression<T>(string propertyName, string propertyValue)
    {
        var parameterExp = Expression.Parameter(typeof(T), "type");
        var propertyExp = Expression.Property(parameterExp, propertyName);
        MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
        var someValue = Expression.Constant(propertyValue, typeof(string));
        var containsMethodExp = Expression.Call(propertyExp, method, someValue);

        return BinaryExpression.Lambda<Func<T, bool>>(containsMethodExp, parameterExp);
    }

应该可以工作,但我可以将Expression转换为BinaryExpression?

有人知道这个或知道其他有效的解决方案吗?

2 个答案:

答案 0 :(得分:0)

我知道问这个问题已经有很长时间了,但是,我认为我已经找到了答案,基本上,答案在MakeBinary上。

首先,我必须创建一个类似Contains的方法,但不能创建一个自引用扩展方法,例如:

public static bool Containss(string text, string text2)
{
    return text.Contains(text2, StringComparison.OrdinalIgnoreCase);
}

然后您像这样使用它:

MethodInfo method = typeof(StackOverflowAnswer).GetMethod("Containss", new[] { typeof(string), typeof(string) });
var constainsExp = Expression.MakeBinary(ExpressionType.Equal, Expression.Constant("FULL TEXT"), Expression.Constant("TEXT"), false, method);

考虑到您的预期目标,可能还会有帮助的事情是接收成员,参数和值以组成最终表达式。这是一个示例:

class StackOverflowAnswer
{
    static void Main()
    {
        ParameterExpression parameter = Expression.Parameter(typeof(Student), typeof(Student).Name);

        var exp1 = GetBinaryExpression(parameter, "Name", "Foo");
        var exp2 = GetBinaryExpression(parameter, "Name", "Bar");
        BinaryExpression[] expressions = new BinaryExpression[] { exp1, exp2 };

        var bin = CombineExpressions(expressions, parameter);
        var func = Expression.Lambda<Func<Student, bool>>(bin, parameter);
        var exp = func.Compile();

        Student student = new Student { Name = "Foo Bar" };

        var x = exp(student);

        Console.WriteLine(x);
    }

    public static BinaryExpression GetBinaryExpression(ParameterExpression parameter, string property, object comparissonValue)
    {
        MemberExpression member = Expression.Property(parameter, property);
        ConstantExpression constant = Expression.Constant(comparissonValue, comparissonValue.GetType());

        MethodInfo method = typeof(StackOverflowAnswer).GetMethod("Containss", new[] { typeof(string), typeof(string) });
        var containsExp = Expression.MakeBinary(ExpressionType.Equal, member, constant, false, method);
        return containsExp ;
    }

    public static BinaryExpression CombineExpressions(BinaryExpression[] expressions, ParameterExpression parameter)
    {
        bool first = true;
        BinaryExpression expFull = expressions[0];
        foreach (BinaryExpression item in expressions)
        {
            if (first)
                first = false;
            else
            {
                expFull = Expression.AndAlso(expFull, item);
            }
        }
        return expFull;
    }

    internal class Student
    {
        public string Name { get; set; }
    }
}

答案 1 :(得分:-2)

 public class FilterExpressionHelper<T> where T : class
{
    public FilterExpressionHelper()
    {
        CriteriaCollection = new List<BinaryExpression>();
    }

    public List<BinaryExpression> CriteriaCollection { get; set; }

    public Expression<Func<T, bool>> NoFilterExpression { get; set; }

    public void RemoveFilterCriteriaFilterDescriptor(Telerik.Windows.Data.FilterDescriptor d)
    {
        string member = d.Member;
        object value = d.Value;

        System.Linq.Expressions.Expression expression = System.Linq.Expressions.Expression.Parameter(typeof(T), "e");

        foreach (var property in member.Split('.'))
        {
            expression = System.Linq.Expressions.Expression.PropertyOrField(expression, property);
        }

        ConstantExpression c = System.Linq.Expressions.Expression.Constant(value, typeof(string));
        BinaryExpression b = System.Linq.Expressions.Expression.Equal(expression, c);

        BinaryExpression expr = CriteriaCollection.Where(cr => cr.Right.ToString() == b.Right.ToString()).FirstOrDefault();

        CriteriaCollection.Remove(expr);
    }

    public void AddFilterCriteriaFilterDescriptor(Telerik.Windows.Data.FilterDescriptor d)
    {
        string member = d.Member;
        object value = d.Value;

        System.Linq.Expressions.Expression expression = System.Linq.Expressions.Expression.Parameter(typeof(T), "e");

        foreach (var property in member.Split('.'))
        {
            expression = System.Linq.Expressions.Expression.PropertyOrField(expression, property);
        }

        ConstantExpression c = System.Linq.Expressions.Expression.Constant(value, value.GetType());

        BinaryExpression b = null;

        switch (d.Operator)
        {
            case FilterOperator.IsEqualTo:

                b = System.Linq.Expressions.Expression.Equal(expression, c);

                break;

            case FilterOperator.Contains:

                //b = GetExpression<T>(expression.ToString(), value.ToString()).Body as BinaryExpression;


                break;

            case FilterOperator.IsGreaterThanOrEqualTo:

                b = System.Linq.Expressions.Expression.GreaterThanOrEqual(expression, c);

                break;

            case FilterOperator.IsLessThanOrEqualTo:


                    b = System.Linq.Expressions.Expression.LessThanOrEqual(expression, c);

                break;
        }


        CriteriaCollection.Add(b);
    }

    public  Expression<Func<T, bool>> GetLambdaExpression()
    {
        ParameterExpression e = System.Linq.Expressions.Expression.Parameter(typeof(T), "e");

        var orderedList = CriteriaCollection.OrderBy(cr => cr.Left.ToString()).ToList();

        var disctinctValues = CriteriaCollection.Distinct(new BinaryExpressionComparer()).ToList();

        List<BinaryExpression> orElseExpressionList = new List<BinaryExpression>();

        foreach (var value in disctinctValues)
        {
            System.Linq.Expressions.BinaryExpression expression = null;

            foreach (var criteria in orderedList.Where(cr => cr.Left.ToString().Equals(value.Left.ToString())))
            {
                if (expression == null)
                {
                    expression = criteria;
                }
                else
                {
                    if (expression.Left.ToString() == criteria.Left.ToString())
                        expression = System.Linq.Expressions.BinaryExpression.OrElse(expression, criteria);
                    else
                        expression = System.Linq.Expressions.BinaryExpression.AndAlso(expression, criteria);

                }
            }

            orElseExpressionList.Add(expression);
        }

        System.Linq.Expressions.BinaryExpression expressionAnd = null;

        foreach (var ex in orElseExpressionList)
        {
            if (expressionAnd == null)
            {
                expressionAnd = ex;
            }
            else
            {
                expressionAnd = System.Linq.Expressions.BinaryExpression.AndAlso(expressionAnd, ex);
            }
        }

        if (expressionAnd != null)
        {
            return System.Linq.Expressions.Expression.Lambda<Func<T, bool>>(expressionAnd, e);
        }
        else
        {
            return NoFilterExpression;
        }
    }

    static Expression<Func<T, bool>> GetExpression<T>(string propertyName, string propertyValue)
    {
        var parameterExp = Expression.Parameter(typeof(T), "type");
        var propertyExp = Expression.Property(parameterExp, propertyName);
        MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
        var someValue = Expression.Constant(propertyValue, typeof(string));
        var containsMethodExp = Expression.Call(propertyExp, method, someValue);

        return BinaryExpression.Lambda<Func<T, bool>>(containsMethodExp, parameterExp);
    }

    private static System.Linq.Expressions.BinaryExpression Like(Expression lhs, Expression rhs)
    {
        //typeof(string).GetMethod("Contains", new Type[] { typeof(string) }, null);

        Expression expression = Expression.Call(
            typeof(FileInfoHelper).GetMethod("Like",
                BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public)
                , lhs, rhs);

        return expression as BinaryExpression;
    }

    class BinaryExpressionComparer : IEqualityComparer<BinaryExpression>
    {
        #region IEqualityComparer<Contact> Members

        public bool Equals(BinaryExpression x, BinaryExpression y)
        {
            return x.Left.ToString().Equals(y.Left.ToString());
        }

        public int GetHashCode(BinaryExpression obj)
        {
            return obj.Left.ToString().GetHashCode();
        }

        #endregion
    }
}