internal ParameterProvider(ParameterExpression parameter, BindingFlags bindingFlags, NullCheckMode nullCheckMode)
 {
     this.parameter     = parameter;
     this.bindingFlags  = bindingFlags;
     this.nullCheckMode = nullCheckMode;
 }
        public Func <T, string> Compile <T>(string formatString, IFormatProvider formatProvider, NullCheckMode nullCheckMode)
        {
            // Guard anyway, since we may be used by things that don't understand nullable reference types
            if (formatString == null)
            {
                throw new ArgumentNullException(nameof(formatString));
            }

            if (formatProvider == null)
            {
                throw new ArgumentNullException(nameof(formatProvider));
            }

            // Parse the string to a set of segments
            IEnumerable <ISegment> segments = ParseFormatString(formatString);

            // Create necessary constant expressions and parameterhelper
            ParameterExpression parameter = Expression.Parameter(typeof(T));
            Expression          formatProviderExpression = Expression.Constant(formatProvider);

            ParameterProvider <T> parameterProvider = new ParameterProvider <T>(parameter, BINDING_FLAGS, nullCheckMode);

            // Compile segments to constituent expressions.
            // Materialize the IEnumerable to a list in order to avoid recalculating the expressions while deciding which concatenation layout to use.
            IEnumerable <Expression> segmentExpressions = segments.Select(s => s.ToExpression <T>(parameterProvider, formatProviderExpression)).ToList();

            // Select the best method of forming the string
            // TODO May be faster to nest concat operations up until a certain point before resorting to allocating an array object in the process. Perhaps a user preference?
            Expression formatExpression;

            if (segments.Count() == 1)
            {
                formatExpression = CompileToSingleton <T>(segmentExpressions.First());
            }
            else if (segments.Count() <= 4)
            {
                formatExpression = CompileToSingleConcat <T>(segmentExpressions);
            }
            else
            {
                formatExpression = CompileToArrayConcat <T>(segmentExpressions);
            }

            // Construct a lambda function from the compiled expression
            return(Expression.Lambda <Func <T, string> >(
                       formatExpression,
                       "FastStringFormatAutogenerated",
                       new ParameterExpression[] { parameter }
                       ).Compile());
        }