The new interpolated string syntax is part compiler magic and part runtime classes.
Let’s go through all the scenarios and see what is actually happening.
-
var s = $"{DateTime.Now}";
This gets compiled as this:
string s = string.Format("{0}", DateTime.Now);
See Try Roslyn for details.
-
string s = $"{DateTime.Now}";
This gets compiled as this:
string s = string.Format("{0}", DateTime.Now);
See Try Roslyn for details.
-
object s = $"{DateTime.Now}";
This gets compiled as this:
object s = string.Format("{0}", DateTime.Now);
See Try Roslyn for details.
-
IFormattable s = $"{DateTime.Now}";
This gets compiled as this:
IFormattable s = FormattableStringFactory.Create("{0}", new object[] { DateTime.Now });
See Try Roslyn for details.
-
FormattableString s = $"{DateTime.Now}";
This gets compiled as this:
FormattableString s = FormattableStringFactory.Create("{0}", new object[] { DateTime.Now });
See Try Roslyn for details.
So we can summarize the compiler magic as follows:
- If we can get by with just using
string
, created with a call toString.Format
, then do that - If not, use
FormattableString
, and create one viaFormattableStringFactory.Create
Since we do not yet have an officiel C# 6 standards document, other than perusing the github repositories, issues, and discussions, the exact rules for this is not known (at least not to me, please prove me wrong!).
So, the above examples shows what happens if the compiler knows the target type, in this case through the variable type. If we call a single method, with no overloads, that has one of those types, the exact same “magic” will happen.
But what happens if we have overloads?
Consider this example:
using System;
public class Program
{
public static void Main()
{
Test($"{DateTime.Now}");
}
public static void Test(object o) { Console.WriteLine("object"); }
public static void Test(string o) { Console.WriteLine("string"); }
public static void Test(IFormattable o) { Console.WriteLine("IFormattable"); }
// public static void Test(FormattableString o) { Console.WriteLine("FormattableString"); }
}
When executing this example we get this output:
string
So clearly string
is still preferred, even when multiple options are available.
See this .NET fiddle for details.
Note that .NET Fiddle for some reason does not allow me to use FormattableString
directly, but if I run the same code, with that overload present, in LINQPad, I still get string
as the output.
If I then remove the string
overload I get FormattableString
, and then if I remove that I get IFormattable
, so with overloads I can then observe that the rules are, and here we stop with the first overload that has:
string
FormattableString
IFormattable
object