/// <summary>
        /// Uses the TraceBuilder rules on the provider to generate the parameter bindings.
        /// </summary>
        /// <param name="methodInfo">The method to analyze.</param>
        /// <returns>A list of ParameterMapping representing the desired bundling of parameters.</returns>
        private IReadOnlyCollection <ParameterMapping> EvaluateBuilders(MethodInfo methodInfo)
        {
            var mappings   = new List <ParameterMapping>();
            var parameters = methodInfo.GetParameters().ToList();

            // give a context rule the opportunity to bind
            parameters.Add(null);

            // get the default name to use for tracing (null if none specified)
            var traceAsDefault = methodInfo.GetCustomAttribute <TraceAsAttribute>();

            foreach (var parameter in parameters)
            {
                bool hasRule = false;

                // go through the rules
                foreach (var builder in _builders.Where(b => b.Matches(methodInfo)))
                {
                    foreach (var value in builder.Values.Where(v => v.Matches(parameter)))
                    {
                        hasRule = true;

                        // if the value is an ignore rule, skip it
                        if (value.Ignore)
                        {
                            continue;
                        }

                        // add the parameter value
                        AddMapping(mappings, parameter, builder.Alias ?? "data", value.Alias ?? builder.Alias ?? "data", value.Converter);
                    }
                }

                // if a rule has been applied, then don't add the base value
                if (hasRule)
                {
                    continue;
                }

                if (parameter == null)
                {
                    continue;
                }

                // if there is a TraceIgnore attribute, then skip this parameter
                if (parameter.GetCustomAttribute <TraceIgnoreAttribute>() != null)
                {
                    continue;
                }

                // we need one parameter per attribute, and at least one per parameter
                var attributes = parameter.GetCustomAttributes <TraceAsAttribute>();
                if (!attributes.Any())
                {
                    attributes = new TraceAsAttribute[1] {
                        traceAsDefault ?? new TraceAsAttribute(parameter.Name)
                    }
                }
                ;

                foreach (var attribute in attributes)
                {
                    var traceName = attribute.Name ?? parameter.Name;

                    var        input      = Expression.Parameter(parameter.ParameterType);
                    Expression expression = input;

                    // if the attribute is a TraceMember, then create an expression to get the member
                    var traceMember = attribute as TraceMemberAttribute;
                    if (traceMember != null)
                    {
                        expression = Expression.MakeMemberAccess(expression, parameter.ParameterType.GetMember(traceMember.Member).First());
                    }

                    // if the attribute is a TraceTransform then validate the usage and use the provided method
                    // to build an expression to apply to the trace value
                    var traceTransform = attribute as TraceTransformAttribute;
                    if (traceTransform != null)
                    {
                        var method = traceTransform.GetTransformMethod(input.Type);
                        if (method == null)
                        {
                            var message = String.Format("{0}.GetTransformMethod() returned null.", attribute.GetType().Name);
                            throw new ArgumentNullException("Method", message);
                        }

                        var methodParams = method.GetParameters();
                        if (methodParams.Length != 1 || method.ReturnType == typeof(void) || !method.IsStatic)
                        {
                            var message = String.Format("{0}.GetTransformMethod() should return MethodInfo for a static method with one input parameter and a non-void response type.", attribute.GetType().Name);
                            throw new ArgumentException(message);
                        }

                        if (methodParams[0].ParameterType != input.Type)
                        {
                            var message = String.Format(
                                "{0}.GetTransformMethod() returned MethodInfo for a static method which expects an input type of '{1}' but was applied to a trace parameter of type '{2}'. (trace method name: {3}, parameter name: {4})",
                                attribute.GetType().Name,
                                methodParams[0].ParameterType,
                                input.Type,
                                methodInfo.Name,
                                traceName);
                            throw new ArgumentException(message);
                        }

                        expression = Expression.Call(method, input);
                    }

                    // if a string format was specified, wrap the expression in a method call
                    if (!String.IsNullOrWhiteSpace(attribute.Format))
                    {
                        var format       = Expression.Constant(attribute.Format);
                        var castAsObject = Expression.Convert(input, typeof(object));
                        expression = Expression.Call(typeof(String).GetMethod("Format", new Type[] { typeof(string), typeof(object) }), format, castAsObject);
                    }

                    // if we did any conversion on the value, then create a lambda function for the conversion
                    LambdaExpression lambda = null;
                    if (expression != input)
                    {
                        lambda = Expression.Lambda(expression, input);
                    }

                    AddMapping(mappings, parameter, traceName, parameter.Name, lambda);
                }
            }

            return(mappings);
        }

        #endregion
    }
        /// <summary>
        /// Uses the TraceBuilder rules on the provider to generate the parameter bindings.
        /// </summary>
        /// <param name="methodInfo">The method to analyze.</param>
        /// <returns>A list of ParameterMapping representing the desired bundling of parameters.</returns>
        private IReadOnlyCollection <ParameterMapping> EvaluateBuilders(MethodInfo methodInfo)
        {
            var mappings   = new List <ParameterMapping>();
            var parameters = methodInfo.GetParameters().ToList();

            // give a context rule the opportunity to bind
            parameters.Add(null);

            // get the default name to use for tracing (null if none specified)
            var traceAsDefault = methodInfo.GetCustomAttribute <TraceAsAttribute>();

            foreach (var parameter in parameters)
            {
                bool hasRule = false;

                // go through the rules
                foreach (var builder in _builders.Where(b => b.Matches(methodInfo)))
                {
                    foreach (var value in builder.Values.Where(v => v.Matches(parameter)))
                    {
                        hasRule = true;

                        // if the value is an ignore rule, skip it
                        if (value.Ignore)
                        {
                            continue;
                        }

                        // add the parameter value
                        AddMapping(mappings, parameter, builder.Alias ?? "data", value.Alias ?? builder.Alias ?? "data", value.Converter);
                    }
                }

                // if a rule has been applied, then don't add the base value
                if (hasRule)
                {
                    continue;
                }

                if (parameter == null)
                {
                    continue;
                }

                // if there is a TraceIgnore attribute, then skip this parameter
                if (parameter.GetCustomAttribute <TraceIgnoreAttribute>() != null)
                {
                    continue;
                }

                // we need one parameter per attribute, and at least one per parameter
                var attributes = parameter.GetCustomAttributes <TraceAsAttribute>();
                if (!attributes.Any())
                {
                    attributes = new TraceAsAttribute[1] {
                        traceAsDefault ?? new TraceAsAttribute(parameter.Name)
                    }
                }
                ;

                foreach (var attribute in attributes)
                {
                    var traceName = attribute.Name;

                    // if the attribute is a TraceMember, then create an expression to get the member
                    LambdaExpression expression = null;
                    var traceMember             = attribute as TraceMemberAttribute;
                    if (traceMember != null)
                    {
                        var input = Expression.Parameter(parameter.ParameterType);
                        expression = Expression.Lambda(
                            Expression.MakeMemberAccess(
                                input,
                                parameter.ParameterType.GetMember(traceMember.Member).First()),
                            input);
                    }

                    AddMapping(mappings, parameter, traceName, parameter.Name, expression);
                }
            }

            return(mappings);
        }

        #endregion
    }