private Action <T> GetConfigurationInvocationAction <T>(MethodInfo configurationMethod,
                                                                MethodInvocationInformation methodCall)
        {
            void ConfigurationAction(T o)
            {
                var    invocationParameters = GetMethodParametersFromMethodCallForConfigurationMethod(methodCall, configurationMethod);
                object invocationTarget     = null;

                if (IsExtensionMethod(configurationMethod))
                {
                    invocationParameters.Insert(0, o);
                }
                else
                {
                    invocationTarget = o;
                }

                var result = configurationMethod.Invoke(invocationTarget, invocationParameters.ToArray());

                methodCall.SubsequentConfigurations.ToList().ForEach(subsequentConfiguration =>
                                                                     InvokeSubsequentConfigurationMethod(subsequentConfiguration, result));
            }

            return(ConfigurationAction);
        }
        private void InvokeSubsequentConfigurationMethod(MethodInvocationInformation methodCall, object invocationSource)
        {
            if (invocationSource == null || methodCall == null)
            {
                return;
            }

            var configurationMethods = FindConfigurationMethods(
                p => p.ParameterType.IsInstanceOfType(invocationSource),
                m => m.DeclaringType == invocationSource.GetType());

            var configurationMethod = FindConfigurationMethodForMethodCall(
                methodCall,
                configurationMethods);

            if (configurationMethod == null)
            {
                return;
            }

            var configurationFunction =
                GetConfigurationInvocationFunction <object>(configurationMethod,
                                                            methodCall);

            var result = configurationFunction(invocationSource);

            methodCall.SubsequentConfigurations.ToList().ForEach(subsequentConfiguration =>
                                                                 InvokeSubsequentConfigurationMethod(subsequentConfiguration, result));
        }
        private void ExecuteMethodCallAsAction <T>(MethodInvocationInformation methodCall,
                                                   IEnumerable <MethodInfo> configurationMethods,
                                                   Func <Action <T>, object> invocationSource)
        {
            var configurationMethod =
                FindConfigurationMethodForMethodCall(methodCall, configurationMethods);

            if (configurationMethod != null)
            {
                var configurationAction = GetConfigurationInvocationAction <T>(configurationMethod, methodCall);

                invocationSource(configurationAction);
            }
        }
        private MethodInfo FindConfigurationMethodForMethodCall(
            MethodInvocationInformation methodCall,
            IEnumerable <MethodInfo> methodInfos)
        {
            var result = methodInfos.FirstOrDefault(m =>
                                                    m.Name.Equals(methodCall.MethodName, StringComparison.OrdinalIgnoreCase) &&
                                                    (IsExtensionMethod(m) &&
                                                     m.GetParameters().Length == methodCall.Parameters.Count + 1 &&
                                                     ParametersMatched(m.GetParameters().Skip(1).ToArray(), methodCall.Parameters) ||
                                                     !IsExtensionMethod(m) &&
                                                     m.GetParameters().Length == methodCall.Parameters.Count &&
                                                     ParametersMatched(m.GetParameters(), methodCall.Parameters)));

            return(result);
        }
        private Func <T, object> GetConfigurationInvocationFunction <T>(MethodInfo configurationMethod,
                                                                        MethodInvocationInformation methodCall)
        {
            object ConfigurationFunction(T o)
            {
                var    invocationParameters = GetMethodParametersFromMethodCallForConfigurationMethod(methodCall, configurationMethod);
                object invocationInstance   = null;

                if (IsExtensionMethod(configurationMethod))
                {
                    invocationParameters.Insert(0, o);
                }
                else
                {
                    invocationInstance = o;
                }
                return(configurationMethod.Invoke(invocationInstance, invocationParameters.ToArray()));
            }

            return(ConfigurationFunction);
        }
        private List <object> GetMethodParametersFromMethodCallForConfigurationMethod(
            MethodInvocationInformation methodCall,
            MethodInfo configurationMethod)
        {
            var result     = new List <object>(methodCall.Parameters.Count + 1);
            var parameters = configurationMethod
                             .GetParameters();

            if (IsExtensionMethod(configurationMethod))
            {
                parameters = parameters.Skip(1).ToArray();
            }

            var methodParameters = parameters
                                   .Select(parameter => methodCall.Parameters.Single(p =>
                                                                                     p.Key == parameter.Name &&
                                                                                     (p.Value != null && parameter.ParameterType.IsInstanceOfType(p.Value) || p.Value == null)
                                                                                     ).Value);

            result.AddRange(methodParameters);

            return(result);
        }