String Interpolation in Visual Studio 2015 and IFormatProvider (CA1305)
Asked Answered
L

4

33

The new string interpolation style in Visual Studio 2015 is this:

Dim s = $"Hello {name}"

But if I use this the code analysis tells me I break CA1305: Specify IFormatProvider

In the old times I did it like this:

Dim s = String.Format(Globalization.CultureInfo.InvariantCulture, "Hello {0}", name)

But how can it be done with the new style?

I have to mention that I'm looking for a solution for .Net 4.5.2 (for .Net 4.6 dcastro has the answer)

Lucent answered 18/8, 2015 at 15:39 Comment(2)
Somebody else totally called it, a whole 7 and a half years ago.Duumvirate
@Duumvirate and they worked around it by allowing you to store the merged format.Estefanaestel
J
10

Microsoft has made it easier to use string interpolation and comply with CA1305: Specify IFormatProvider.

If you are using C# 6 or later, you have access to the using static directive.

In addition, the static method FormattableString.Invariant is available for .NET Standard 1.3, .NET Core 1.0 and .NET Framework 4.6 and later. Putting the two together allows you to do this:

using static System.FormattableString;

string name = Invariant($"Hello {name}");

If, however, your goal is for the interpolation to be done via the current culture, then a companion static method FormattableString.CurrentCulture is proposed in .NET Core 3.0 (currently, Preview 5):

using static System.FormattableString;

string name = CurrentCulture($"Hello {name}");
Jesuit answered 6/5, 2019 at 20:18 Comment(0)
E
23

You'd use the System.FormattableString or System.IFormattable class:

IFormattable ifs = (IFormattable)$"Hello, {name}";
System.FormattableString fss = $"Hello, {name}";

// pass null to use the format as it was used upon initialization above.
string ifresult = ifs.ToString(null, CultureInfo.InvariantCulture);
string fsresult = fss.ToString(CultureInfo.InvariantCulture);

You need to be compiling against Framework 4.6, as the IFormattable and FormattableString are classes which do not exist in older versions. So if you're targeting older versions of the .NET framework you can't use the interpolation syntax without triggering the error.

Unless you apply a little hack (adapted to compile against 4.6 RTM from Jon Skeet's gist and forked to my own account.). Just add a class file to your project containing:

Update

There is now also a Nuget package available that will provide the same functionality to your project (thanks for bringing this to my attention @habakuk).

install-package StringInterpolationBridge

Or if you want to achieve the same thing without adding an additional assembly to your product add the following code to your project:

namespace System.Runtime.CompilerServices
{
    internal class FormattableStringFactory
    {
        public static FormattableString Create(string messageFormat, params object[] args)
        {
            return new FormattableString(messageFormat, args);
        }
    }
}

namespace System
{
    internal class FormattableString : IFormattable
    {
        private readonly string messageFormat;
        private readonly object[] args;

        public FormattableString(string messageFormat, object[] args)
        {
            this.messageFormat = messageFormat;
            this.args = args;
        }

        public override string ToString()
        {
            return string.Format(messageFormat, args);
        }

        public string ToString(string format, IFormatProvider formatProvider)
        {
            return string.Format(formatProvider, format ?? messageFormat, args);
        }

        public string ToString(IFormatProvider formatProvider)
        {
            return string.Format(formatProvider, messageFormat, args);
        }
    }
}

See:

Estefanaestel answered 18/8, 2015 at 15:58 Comment(2)
This implementation differs a little from the one shipped with .NET 4.6. In particular .NET ignores the format parameter on IFormattable.ToString(string,IFormatProvider) It is probably easier to just copy the source code directly from the CLR, like StringInterpolationBridge does: github.com/dotnet/coreclr/blob/master/src/mscorlib/src/System/… github.com/dotnet/coreclr/blob/master/src/mscorlib/src/System/…Saxophone
Also, if you are using .NET 4.6 or StringInterpolationBridge, there is a helper method you can use to make culture string: FormattableString.Invariant: msdn.microsoft.com/en-us/library/…Saxophone
L
12

If you're targeting the .NET Framework 4.6, you can take advantage of the fact that string interpolations are implicitly convertible to FormattableString:

From Customizing string interpolation in C# 6 by Thomas Levesque

A lesser known aspect of this feature is that an interpolated string can be treated either as a String, or as an IFormattable, depending on the context.

static string Invariant(FormattableString formattable)
{
    return formattable.ToString(CultureInfo.InvariantCulture);
}

string text = Invariant($"{p.Name} was born on {p.DateOfBirth:D}");
Lockyer answered 18/8, 2015 at 15:51 Comment(5)
Thanks, but I'm still on 4.5.2 (because of blogs.msdn.com/b/dotnet/archive/2015/07/28/… - But it is probably fixed now). Is there also a solution for 4.5?Lucent
@Lucent No, I don't think so.Lockyer
Note that the bug why you're still on 4.5.2 has been fixed. Run Windows Update to solve the issue.Estefanaestel
@Lucent If you read the linked Levesque article it seems there is! Check out Jon Skeet's methodLockwood
@Lockwood that gist unfortunately no longer works, but it isn't hard to fix it. See my answer.Estefanaestel
J
10

Microsoft has made it easier to use string interpolation and comply with CA1305: Specify IFormatProvider.

If you are using C# 6 or later, you have access to the using static directive.

In addition, the static method FormattableString.Invariant is available for .NET Standard 1.3, .NET Core 1.0 and .NET Framework 4.6 and later. Putting the two together allows you to do this:

using static System.FormattableString;

string name = Invariant($"Hello {name}");

If, however, your goal is for the interpolation to be done via the current culture, then a companion static method FormattableString.CurrentCulture is proposed in .NET Core 3.0 (currently, Preview 5):

using static System.FormattableString;

string name = CurrentCulture($"Hello {name}");
Jesuit answered 6/5, 2019 at 20:18 Comment(0)
L
4

I have found a Nuget-Package that covers the code that jessehouwing presented in his answer.

The Nuget package 'StringInterpolationBridge' (source) adds this code to every project.

Lucent answered 24/8, 2015 at 12:58 Comment(1)
I hope you don't mind me addign this gem to the already accepted answer for completeness. Thanks for bringing it to my attention!Estefanaestel

© 2022 - 2024 — McMap. All rights reserved.