protected override Expression VisitBinary(BinaryExpression node)
        {
            // Note that we're turning shortcutting operators into, well, not.
            switch (node.NodeType)
            {
            case ExpressionType.And:
            case ExpressionType.AndAlso:
                if (node.Left.Type == typeof(bool) && node.Right.Type == typeof(bool))
                {
                    return(this.Visit(LdapExpressionFactory.And(new[] { node.Left, node.Right })));
                }
                break;

            case ExpressionType.Or:
            case ExpressionType.OrElse:
                if (node.Left.Type == typeof(bool) && node.Right.Type == typeof(bool))
                {
                    return(this.Visit(LdapExpressionFactory.Or(new[] { node.Left, node.Right })));
                }
                break;

            default:
                break;
            }
            return(base.VisitBinary(node));
        }
        protected override Expression VisitNary(NaryExpression node)
        {
            Expression result = base.VisitNary(node);

            node = result as NaryExpression;
            if (node == null)
            {
                return(result);
            }

            switch ((LdapExpressionType)node.NodeType)
            {
            case LdapExpressionType.And:
                // (& X, false) -> false
                if (node.Clauses.Any(c => c.IsConstant(false)))
                {
                    return(False);
                }
                // If any of the sub-clauses is true, then the 'and' is not affected by them.
                var andClauses = node.Clauses.Where(c => !c.IsConstant(true));
                switch (andClauses.Count())
                {
                case 0:
                    // This is trivially true.
                    // (& true) -> true
                    return(True);

                case 1:
                    // Just return the sub-clause.
                    // (& true, X) -> X
                    return(andClauses.First());

                default:
                    if (andClauses.Count() == node.Clauses.Count)
                    {
                        // No changes
                        // (& X, Y) -> (& X, Y)
                        return(node);
                    }
                    else
                    {
                        // (& true, X, Y) -> (& X, Y)
                        //return node.Update( andClauses );
                        return(LdapExpressionFactory.And(andClauses));
                    }
                }

            case LdapExpressionType.Or:
                // (| X, true) -> true
                if (node.Clauses.Any(c => c.IsConstant(true)))
                {
                    return(True);
                }
                // If any of the sub-clauses is false, then the 'or' is not affected by them.
                var orClauses = node.Clauses.Where(c => !c.IsConstant(false));
                switch (orClauses.Count())
                {
                case 0:
                    // This is trivially false
                    // (| false) -> false
                    return(False);

                case 1:
                    // Just return the sub-clause.
                    // (| false, X) -> X
                    return(orClauses.First());

                default:
                    if (orClauses.Count() == node.Clauses.Count)
                    {
                        // No changes
                        // (| X, Y) -> (| X, Y)
                        return(node);
                    }
                    else
                    {
                        // (| X, Y, false) -> (| X, Y)
                        //return node.Update( orClauses );
                        return(LdapExpressionFactory.And(orClauses));
                    }
                }

            default:
                // Some other type of Nary expression...
                return(node);
            }
        }