public static Expression <T> ApplyUnary <T>(this Expression <T> self, Func <Expression, Expression> unaryExpr)
            where T : class
        {
            if (self == null)
            {
                return(null);
            }
            if (unaryExpr == null)
            {
                throw new ArgumentNullException(nameof(unaryExpr));
            }

            var parameters = self.CloneParameters();

            self = self.Update(self.RebindBodyParametersWith(parameters), parameters);

            return(Expression.Lambda <T>(unaryExpr(self.Body), parameters));
        }
        public static Expression <Func <T, bool> > CombineBinary <T, R>(this Expression <Func <T, R> > self, Expression <Func <T, R> > expression, Func <Expression, Expression, BinaryExpression> combinator, ParameterExpression[] parameters = null)
            where T : class
        {
            if (self == null)
            {
                throw new ArgumentNullException(nameof(self));
            }
            if (expression == null)
            {
                throw new ArgumentNullException(nameof(expression));
            }
            if (combinator == null)
            {
                throw new ArgumentNullException(nameof(combinator));
            }

            if (parameters == null)
            {
                // parameters can be on different levels of hierarchy so we should choose higher level parameter as a target for cloning
                parameters = self.Parameters.First().Type.IsAssignableFrom(expression.Parameters.First().Type) ? expression.CloneParameters() : self.CloneParameters();
            }

            self       = self.Update(self.RebindBodyParametersWith(parameters), parameters);
            expression = expression.Update(expression.RebindBodyParametersWith(parameters), parameters);
            var combined = combinator(self.Body, expression.Body);

            return(Expression.Lambda <Func <T, bool> >(combined, parameters));
        }