public static Expression BindMethodExpression(MethodCallExpression m, bool allowPolymorphics)
        {
            if (m.Method.DeclaringType == typeof(ExpressionExtensions) && m.Method.Name == "Evaluate")
            {
                LambdaExpression lambda = (LambdaExpression)(ExpressionEvaluator.Eval(m.Arguments[0]));

                return(Expression.Invoke(lambda, m.Arguments.Skip(1).ToArray()));
            }

            if (m.Method.HasAttributeInherit <PolymorphicExpansionAttribute>() && !allowPolymorphics)
            {
                return(null);
            }

            MethodExpanderAttribute attribute = m.Method.GetCustomAttribute <MethodExpanderAttribute>();

            if (attribute != null)
            {
                if (attribute.ExpanderType.IsGenericTypeDefinition)
                {
                    if (!typeof(GenericMethodExpander).IsAssignableFrom(attribute.ExpanderType))
                    {
                        throw new InvalidOperationException("Expansion failed, '{0}' does not implement IMethodExpander or GenericMethodExpander".FormatWith(attribute.ExpanderType.TypeName()));
                    }

                    Expression[] args = m.Object == null?m.Arguments.ToArray() : m.Arguments.PreAnd(m.Object).ToArray();

                    var type = attribute.ExpanderType.MakeGenericType(m.Method.GetGenericArguments());
                    GenericMethodExpander expander = Activator.CreateInstance(type) as GenericMethodExpander;
                    return(Expression.Invoke(expander.GenericLambdaExpression, args));
                }
                else
                {
                    if (!typeof(IMethodExpander).IsAssignableFrom(attribute.ExpanderType))
                    {
                        throw new InvalidOperationException("Expansion failed, '{0}' does not implement IMethodExpander or GenericMethodExpander".FormatWith(attribute.ExpanderType.TypeName()));
                    }

                    IMethodExpander expander = (IMethodExpander)Activator.CreateInstance(attribute.ExpanderType);

                    Expression exp = expander.Expand(
                        m.Object,
                        m.Arguments.ToArray(),
                        m.Method);

                    return(exp);
                }
            }

            LambdaExpression lambdaExpression = GetFieldExpansion(m.Object?.Type, m.Method);

            if (lambdaExpression != null)
            {
                Expression[] args = m.Object == null?m.Arguments.ToArray() : m.Arguments.PreAnd(m.Object).ToArray();

                return(Expression.Invoke(lambdaExpression, args));
            }

            return(null);
        }
        internal override Expression VisitMethodCall(MethodCallExpression m)
        {
            // Expand expression tree 'calls'
            object[] attrs = m.Method.GetCustomAttributes(typeof(MethodExpanderAttribute), false);
            if (attrs.Length > 0)
            {
                MethodExpanderAttribute attr = (MethodExpanderAttribute)attrs[0];
                IMethodExpander         exp  = Activator.CreateInstance(attr.ExpanderType) as IMethodExpander;
                if (exp == null)
                {
                    throw new InvalidOperationException(string.Format(
                                                            "LINQ method mapping expansion failed! Type '{0}' does not implement IMethodExpander interface.",
                                                            attr.ExpanderType.Name));
                }
                return(exp.Expand(Visit(m.Arguments[0]), m.Arguments.Skip(1).Select(p => Visit(p))));
            }

            if (m.Method.DeclaringType == typeof(ExpressionExtensions))
            {
                LambdaExpression lambda = (LambdaExpression)(Evaluate(m.Arguments[0]));

                Dictionary <ParameterExpression, Expression> replaceVars
                    = new Dictionary <ParameterExpression, Expression>();
                for (int i = 0; i < lambda.Parameters.Count; i++)
                {
                    Expression rep = m.Arguments[i + 1];
                    if ((_replaceVars != null) && (rep is ParameterExpression) && (_replaceVars.ContainsKey((ParameterExpression)rep)))
                    {
                        replaceVars.Add(lambda.Parameters[i], _replaceVars[(ParameterExpression)rep]);
                    }
                    else
                    {
                        replaceVars.Add(lambda.Parameters[i], rep);
                    }
                }
                if (_replaceVars != null)
                {
                    foreach (KeyValuePair <ParameterExpression, Expression> pair in _replaceVars)
                    {
                        replaceVars.Add(pair.Key, pair.Value);
                    }
                }
                return(new ExpressionExpander(replaceVars).Visit(lambda.Body));
            }
            return(base.VisitMethodCall(m));
        }