Получите все вызовы «где» с помощью ExpressionVisitor

У меня есть запрос, например:

var query = from sessions in dataSet
                    where (names.Contains(sessions.Username))
                    where (sessions.Login.TimeOfAction == dt)                    
                    select new {    sessions.Username, 
                                    sessions.Login, 
                                    sessions.Logout, sessions.Duration };

Я хочу реализовать ExpressionVisitor для извлечения ОБА предложений where как Lambda, но до сих пор мне удалось получить только первое, используя класс под названием «InnermostWhereFinder», который взят из учебника MSDN по пользовательскому поставщику запросов для веб-службы TerraServer. .

It is:

internal class InnermostWhereFinder : ExpressionVisitor
    {
        private MethodCallExpression innermostWhereExpression;

        public MethodCallExpression GetInnermostWhere(Expression expression)
        {
            Visit(expression); 
            return innermostWhereExpression;
        }

        protected override Expression VisitMethodCall(MethodCallExpression expression)
        {
            if (expression.Method.Name == "Where")
                innermostWhereExpression = expression;

            Visit(expression.Arguments[0]);

            return expression;
        }
    }

Я пытался сильно настроить этот класс, чтобы вернуть оба пункта where, но безуспешно. Не удалось найти никакой отличной документации по этому вопросу, может ли кто-нибудь помочь? Я думаю, что в конечном итоге это должно привести к созданию нескольких объектов LambdaExpression, с которыми я смогу работать.


person Sean    schedule 23.12.2010    source источник


Ответы (1)


Используйте класс, найденный здесь http://msdn.microsoft.com/en-us/library/bb882521%28v=vs.90%29.aspx в качестве основы. Затем вы можете создать своего посетителя следующим образом

internal class WhereFinder : ExpressionVisitor
    {
        private IList<MethodCallExpression> whereExpressions = new List<MethodCallExpression>();

        public IList<MethodCallExpression> GetWhere(Expression expression)
        {
            Visit(expression); 
            return whereExpressions;
        }

        protected override Expression VisitMethodCall(MethodCallExpression expression)
        {
            if (expression.Method.Name == "Where")
                whereExpressions.Add(expression);

            Visit(expression.Arguments[0]);

            return expression;
        }
    }
person Vadim    schedule 23.12.2010
comment
Спасибо, это работает. Еще один вопрос... знаете ли вы, возможно ли также удалить некоторые пункты where из дерева Exp? - person Sean; 23.12.2010
comment
В вашем VisitMethodCall, где вы добавляете выражение в список. Вы можете сделать какой-то тест, а затем вместо возврата выражения вы можете заменить второй аргумент постоянным условием. Что-то вроде 1 == 1 - person Vadim; 23.12.2010