Search
Close this search box.

C#/.NET Little Wonders: String Interpolation in C# 6

Once again, in this series of posts I look at the parts of the .NET Framework that may seem trivial, but can help improve your code by making it easier to write and maintain. The index of all my past little wonders posts can be found here. 

Visual Studio 2015 is on the horizon!  In fact, some of you may already have played with the preview and seen some of the many neat new things to come – both in the IDE and in the C# language.

For those who haven’t been keeping up with the announcements, allow me to take some blog time for the next few Little Wonders posts to talk about some of the neat new things that will be part of C# 6. 

Then, once it’s available for you to consume, you can hit the ground running with an arsenal of new little ways to make your code cleaner and more maintainable.

Update: As of the latest technology preview, the syntax has changed for interpolated strings.  I’ve updated the blog post to reflect this.

String Formatting

Often times, when you want to log information to a file, console, or status label you end up having to format that information into a string.  There are, of course, several ways to do this.  The problem is that the more complex your formatting gets, the harder it is to understand and maintain the code.

For example, let’s say we have a very simple class representing a Point:

public class Point {
  public int X { get; set; }
  public int Y { get; set; }
}

And we have a pair of points (perhaps bounding a rectangle) that we wish to log:

var p1 = new Point { X = 5, Y = 10 };
var p2 = new Point { X = 7, Y = 3 };

We could, of course, perform string concatenation to do this:

Console.WriteLine("The area of interest is bounded by (" + p1.X + "," + p1.Y +
                  ") and (" + p2.X + "," + p2.Y + ")");

This works fine and performs relatively well (multiple string concatenations in the same statement are generally optimized with a behind-the-scenes StringBuilder).  However, the problem is that the more things we concatenate together, the harder it is to understand the original intention of the output statement because it is broken up by multiple opening and closing quotes and the concatenation operator (+).

To some extent, we can make this a bit better by using String.Format() and other methods (such as Console.WriteLine) that accept a format, for example:

Console.WriteLine("The area of interest is bounded by({0},{1}) and ({2},{3})",
                  p1.X, p1.Y, p2.X, p2.Y);

This solves the problem of breaking up the formatting with quotation marks and the concatenation operator, however, it also creates new problems. 

First of all, you have to maintain the position of the placeholders and the order of the arguments.  Thus, if you need to add a new item earlier in the string, you’d either have to bump up all the other indexes or add the new item at the end and have your placeholders out of order:

// inserting before means bumping the index of each other placeholder up
Console.WriteLine("The area of interest for {0} is bounded by({1},{2}) and ({3},{4})",
    "My Rectangle", p1.X, p1.Y, p2.X, p2.Y);
 
// putting it at the end means your arguments are not in their actual display order
Console.WriteLine("The area of interest for {4} is bounded by({0},{1}) and ({2},{3})", 
    p1.X, p1.Y, p2.X, p2.Y, "My Rectangle");

Neither of these are fully desirable since you now have to make sure any change you make to the string or arguments keeps the two in sync.  And this can be especially bad if you have a placeholder for an argument index that no longer exists:

// Oops, Removed the argument, but forgot the placeholder
Console.WriteLine(
    "The area of interest for {4} is bounded by({0},{1}) and ({2},{3})", p1.X,
    p1.Y, p2.X, p2.Y);

It isn’t a compiler error, but a runtime error, which may pop up when you least expect it, especially if it’s not on a well travelled code branch:

Unhandled Exception
    : System
          .FormatException
    : Index(zero based) must be greater than or equal to zero and less than the
      size of the argument list.at System.Text.StringBuilder
          .AppendFormatHelper(IFormatProvider provider, String format,
                              ParamsArray args) at System.String
          .FormatHelper(IFormatProvider provider, String format,
                        ParamsArray args) at System.String
          .Format(IFormatProvider provider, String format,
                  Object[] args) at System.IO.TextWriter
          .WriteLine(String format, Object[] arg) at System.IO.TextWriter
          .SyncTextWriter.WriteLine(String format, Object[] arg) at System
          .Console.WriteLine(String format, Object[] arg) at VNextScratchpad
          .Program.Main(String[] args) in C :\source\VNextScratchpad\Program.cs
    : line 31

There has to be a happy medium between the two.  On one hand, concatenation is nice because it has everything right in its actual place in the string, but the syntax is cumbersome as the string gets longer.  On the other hand, formatting is nice because it makes the string very clean but then it separates the placeholders from the arguments.

Well, that is what string interpolation sets out to fix in C# 6.  This is a concept that languages like Perl have had for quite a while, and now we’ll get this ability in C# as well.

So, to unlock this ability, we simply prefix the string with a $ (much like we use the @ for verbatim strings).  Then, we simply surround the expressions we want to interpolate with curly braces (i.e. { and }):

For example, the line of output from before now looks like:

// notice how the expressions are now embedded in the string itself
Console.WriteLine($"The area of interest is bounded by ({p1.X},{p1.Y}) and ({p2.X},{p2.Y})");

It looks a lot like the String.Format() placeholders, but instead of an index, it is the expression itself inside the curly braces.  In fact, it shouldn’t be a surprise that it looks like String.Format() because that’s really all it is – syntactical sugar that the compiler treats like String.Format() behind the scenes.

A great part is, the compiler now maintains the placeholders for you so you don’t have to worry about indexing the right argument because you simply place it right there in the string.

Advanced Formatting with Interpolation

Because interpolation is really compile-time magic and syntactical sugar for String.Format(), you can use alignment and format arguments (See the MSDN on Composite Formatting) in the placeholder as well. 

Consider the syntax for a format element placeholder:

{index[,alignment][:formatString]}

The only difference with interpolation is that we will replace the index with the expression. 

For example, consider the code on the MSDN Composite Formatting page:

for (int ctr = 0; ctr < names.Length; ctr++)
{
   Console.WriteLine("{0,-20} {1,5:N1}", names[ctr], hours[ctr]);
}

We can change this to take advantage of interpolation and make it:

for (int ctr = 0; ctr < names.Length; ctr++)
{
    Console.WriteLine($"{names[ctr],-20} {hours[ctr],5:N1}");
}

This means that names[ctr]’s value will be left justified and padded to 20 spaces, and hours[ctr]’s value will take 5 spaces and be formatted as a number digit behind the decimal point.

This feature is currently available in the preview for VisualStudio 2015 and C# 6, though it’s possible they may simplify the syntax in the final release.  In fact, if you have an older version of the 2015 CTP you’ll note that there is not a $ string prefix, and the placeholders are marked with an escape backslash first.

Summary

String interpolation is yet another tool that will be coming out in C# 6 that will allow you to make code easier to maintain.  By embedding the values directly in the string to print, there is less confusion as to what values go with what placeholder – but you still maintain the ability to specify formatting as well.

Stay tuned for more Little Wonders of C# 6!

This article is part of the GWB Archives. Original Author: James Michael Hare

Related Posts