C# 6.0 String Interpolation, FormattableString, and Code Analysis CA1305: Specify IFormatProvider

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.

17 Comments

  • Never thought about it.

  • Now I start to understand something more clearly! it's cool!

  • Thank you for this explanation! Even though it is still annoying, at least it solves my problem with the Code Analysis warnings!

  • Using Invariant everywhere defeats any culture-sensitive string formatting. That can be good if a machine will parse your string later. But if it's for human presentation, you should keep it culture sensitive. You can do this with string interpolation, although it's less convenient:

    static string StringInterpolation_CultureSensitive()
    {
    return ((FormattableString)$"hi {3 + 5}").ToString(CultureInfo.CurrentCulture);
    }

    static string StringInterpolation_WithInvariant()
    {
    return Invariant($"hi {3 + 5}");
    }

  • @Andrew Arnott, Calling .ToString() is already culture-sensitive. See https://gist.github.com/binki/d2457e592c51b507cb77bb1c877e3175 and the documentation for FormattableString.ToString() (the overload taking no arguments talks about how it works “by using the formatting conventions of the current culture”). So, with string interpolation, supporting the current culture is actually quite easy. Just use let it compile as something that evaluates to string rather than something else and you’re done!

  • i was having some difficulties with this code

    internal static class Program

  • https://ma-study.blogspot.com/

  • This blog is very beneficial to us. Thank you for writing about it. In this article, some examples help me apply to my daily life. 메이저토토

  • Everyone is to blame for sharing particularly amazing posts. It was really worth it. Continue to share more material. 메이저토토사이트

  • I want you to know that Your article is one of the ones that really caught my attention. I want to receive this kind of knowledge every day. I will follow your article.

  • Good article, I really like the content of this article. I really like your article. Thank you for sharing such a great article.

  • I'm writing on this topic these days, <a href="https://toolbarqueries.google.mg/url?sa=t&url=https%3A%2F%2Fwww.mtclean.blog/">totosite</a>, but I have stopped writing because there is no reference material. Then I accidentally found your article. I can refer to a variety of materials, so I think the work I was preparing will work! Thank you for your efforts.

  • I've been looking for photos and articles on this topic over the past few days due to a school assignment, <a href="https://toolbarqueries.google.lv/url?sa=t&url=https%3A%2F%2Fwww.mtclean.blog/">baccarat online</a> and I'm really happy to find a post with the material I was looking for! I bookmark and will come often! Thanks :D

  • I've been troubled for several days with this topic. <a href="https://toolbarqueries.google.lu/url?sa=t&url=https%3A%2F%2Fwww.mtclean.blog/">casinosite</a>, But by chance looking at your post solved my problem! I will leave my blog, so when would you like to visit it?

  • The assignment submission period was over and I was nervous, <a href="https://toolbarqueries.google.lt/url?sa=t&url=https%3A%2F%2Fwww.mtclean.blog/">baccaratsite</a> and I am very happy to see your post just in time and it was a great help. Thank you ! Leave your blog address below. Please visit me anytime.

  • I didn't expect to receive any new news from here. Everything looks different but interesting in itself.

  • I came to this site with the introduction of a friend around me and I was very impressed when I found your writing.

Add a Comment

As it will appear on the website

Not displayed

Your website