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()); }