C# 6.0 introduces a syntactic sugar string interpolation, it is safer and more readable than composite formatting. Here is a small example:
using System;using System.Diagnostics;
internal static class Program{ private static void Main() => Trace.WriteLine($"Machine name: {Environment.MachineName}.");}However, string interpolation does not get along with code analysis. By default, the $ syntax will be compiled to composite formatting, by calling the string.Format overload without IFormatProvider parameter:
using System;using System.Diagnostics;
internal static class Program{ private static void Main() => Trace.WriteLine(string.Format("Machine name: {0}.", Environment.MachineName));}As a result, Code Analysis/FxCop issues a CA1305 warning for every interpolated string: Specify IFormatProvider. This is very annoying.
Interpolated string has a infamous feature, it can be also compiled to System.FormattableString:
namespace System{ using System.Globalization;
public abstract class FormattableString : IFormattable { protected FormattableString() { }
public abstract string Format { get; }
public abstract int ArgumentCount { get; }
public abstract object[] GetArguments();
public abstract object GetArgument(int index);
public abstract string ToString(IFormatProvider formatProvider);
string IFormattable.ToString(string ignored, IFormatProvider formatProvider) => this.ToString(formatProvider);
public static string Invariant(FormattableString formattable) { if (formattable == null) { throw new ArgumentNullException(nameof(formattable)); }
return formattable.ToString(CultureInfo.InvariantCulture); }
public override string ToString() => this.ToString(CultureInfo.CurrentCulture); }}Here FormattableString.Invariant seems to be a solution. Notice FormattableString is an abstract class. It is inherited by System.Runtime.CompilerServices.FormattableStringFactory.ConcreteFormattableString:
namespace System.Runtime.CompilerServices{ public static class FormattableStringFactory { private sealed class ConcreteFormattableString : FormattableString { private readonly string _format;
private readonly object[] _arguments;
public override string Format => this._format;
public override int ArgumentCount => this._arguments.Length;
internal ConcreteFormattableString(string format, object[] arguments) { this._format = format; this._arguments = arguments; }
public override object[] GetArguments() => this._arguments;
public override object GetArgument(int index) => this._arguments[index];
public override string ToString (IFormatProvider formatProvider) => string.Format(formatProvider, this._format, this._arguments); }
public static FormattableString Create(string format, params object[] arguments) { if (format == null) { throw new ArgumentNullException(nameof(format)); }
if (arguments == null) { throw new ArgumentNullException(nameof(arguments)); }
return new ConcreteFormattableString(format, arguments); } }}So that, FormattableString.Invariant calls ConcreteFormattableString.ToString, which then calls string.Format, the overload with IFormatProvider. Code Analysis warning CA1305: Specify IFormatProvider can be fixed as:
using System;using System.Diagnostics;
using static System.FormattableString;
internal static class Program{ private static void Main() => Trace.WriteLine(Invariant($"Machine name: {Environment.MachineName}."));}Above interpolated string is compiled to composite formatting call to FormattableStringFactory.Create:
using System;using System.Diagnostics;using System.Runtime.CompilerServices;
using static System.FormattableString;internal static class Program{ private static void Main() => Trace.WriteLine(Invariant( // $"Machine name: {Environment.MachineName}." is compiled to: FormattableStringFactory.Create("Machine name: {0}.", Environment.MachineName)));}So the conclusion is, to fix Code Analysis CA1305 for C# 6.0 string interpolation, FormattableString.Invariant has to be called for every occurrence of $ syntax. This is still very annoying. Hope there can be another syntactic sugar for this, for example, a $$ prefix to call FormattableString.Invariant.
Also, MSDN and many other articles are inaccurate about interpolated string and FormattableString. MSDN says:
There are implicit type conversions from an interpolated string
In .NET, the term “implicit type conversion” is usually about runtime behavior, implemented by calling a type conversion operator defined with the implicit keyword. However, as demonstrated above, interpolated string becomes FormattableString/IFormattable at compile time.