James Michael Hare

...hare-brained ideas from the realm of software development...
posts - 166 , comments - 1488 , trackbacks - 0

My Links

News

Welcome to my blog! I'm a Sr. Software Development Engineer in the Seattle area, who has been performing C++/C#/Java development for over 20 years, but have definitely learned that there is always more to learn!

All thoughts and opinions expressed in my blog and my comments are my own and do not represent the thoughts of my employer.

Blogs I Read

Follow BlkRabbitCoder on Twitter

Tag Cloud

Archives

Post Categories

.NET

CSharp

Little Wonders

Little Wonders

vNext

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:

   1: public class Point
   2: {
   3:     public int X { get; set; }
   4:     public int Y { get; set; }
   5: }

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

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

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

   1: Console.WriteLine("The area of interest is bounded by (" 
   2:     + 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:

   1: Console.WriteLine("The area of interest is bounded by({0},{1}) and ({2},{3})", 
   2:     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:

   1: // Oops, Removed the argument, but forgot the placeholder
   2: Console.WriteLine("The area of interest for {4} is bounded by({0},{1}) and ({2},{3})", 
   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:

   1: Unhandled Exception: System.FormatException: Index (zero based) must be greater than or equal to zero and less than the size of the argument list.
   2:    at System.Text.StringBuilder.AppendFormatHelper(IFormatProvider provider, String format, ParamsArray args)
   3:    at System.String.FormatHelper(IFormatProvider provider, String format, ParamsArray args)
   4:    at System.String.Format(IFormatProvider provider, String format, Object[] args)
   5:    at System.IO.TextWriter.WriteLine(String format, Object[] arg)
   6:    at System.IO.TextWriter.SyncTextWriter.WriteLine(String format, Object[] arg)
   7:    at System.Console.WriteLine(String format, Object[] arg)
   8:    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 1 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!

Print | posted on Thursday, March 26, 2015 9:39 PM | Filed Under [ My Blog C# Software .NET Little Wonders vNext ]

Feedback

Gravatar

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

I think the syntax has slightly changed and will be like:
$"The area of interest is bounded by ({p1.X},{p1.Y}) and ({p2.X},{p2.Y})"

https://github.com/dotnet/roslyn/wiki/Languages-features-in-C%23-6-and-VB-14
3/27/2015 5:05 AM | Mariusz Pawelski
Gravatar

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

Thanks for this C# 6 series. It's been fun to see what is new. I love how streamlined these changes make the code.
3/27/2015 8:57 AM | Amy
Gravatar

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

@Mariusz, yes, i believe that is the new proposed syntax. I was mainly focussing what was out in the current preview of VS2015 available from MSDN. I hope to update this as we get closer to the release :-)

Thanks for calling that out more clearly.
3/27/2015 9:55 AM | James Hare
Gravatar

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

@Amy: you're quite welcome! I'm excited for these changes as well.
3/27/2015 9:55 AM | James Hare
Gravatar

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

I'm excited about the new string interpolation. The runtime error problem is such a pain with string.format that I've been surprised there wasn't editor or compiler help with that as a special case - if we can do Intellisense/autocomplete, this should have been easy.

But now there's another way! Very cool.
3/27/2015 10:29 AM | Joel
Gravatar

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

Good to hear about the new syntax. I hated the current one. I was going to suggest: #"The area of interest is bounded by ({p1.X},{p1.Y}) and ({p2.X},{p2.Y})" but a dollar sign is good too.
3/27/2015 1:46 PM | James Curran
Gravatar

# not useful for localized applications

If you're using string resources this feature gets you nothing 😓
3/28/2015 3:26 PM | freeandnil
Gravatar

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

I'm happy to see the feature, but I'm a bit disappointed by the syntax. The $"" is an improvement, but I argued for (I think) a much simpler approach in the Roslyn forum: postfix notation for string concatenation. E.g.:

var s = "The area of interest is bounded by "p1.X", "p1.Y") and ("p2.X", "p2.Y")"+;

The variable portions remain *outside* the string with this syntax. This allows for rich, flexible variable expressions, simpler parsing, full IDE color/Intellisense support, and the option to use line breaks in the expression for readability. It uses the same number of characters as the {brace} interpolation, while not introducing *any* new punctuation.

The advantage of interpolation over this approach is easier access to format strings, but I don't see that as an insurmountable problem.
4/3/2015 10:33 AM | Richard Tallent
Post A Comment
Title:
Name:
Email:
Comment:
Verification:
 

Powered by: