22

So, I've just had the following conversation with a user in the comments section.

Me:

Year year = new Year{ State = States.Happy };

Them:

eventStream.ReceiveJoke += joke =>  
    Console.WriteLine($"Pretty nice joke: {joke}, Thanks!!!");

And, nerdy as I am, I wonder what he meant by the dollar sign but I think it's too embarrassing to ask him.

Community
  • 1
  • 1
Konrad Viltersten
  • 36,151
  • 76
  • 250
  • 438
  • 9
    Konrad, there is no problem to ask me about it, I love help people :D – Alberto Monteiro Jan 01 '16 at 18:13
  • 2
    @AlbertoMonteiro You were **not** supposed to see this. I wanted to get back to you with an even more witty comment. Darn... *year.State = States.Darn;* – Konrad Viltersten Jan 01 '16 at 18:22
  • I saw and already answered this question :P – Alberto Monteiro Jan 01 '16 at 18:24
  • I don't want to edit in case I've missed your reasoning, but I suggest asking what it *does* mean, not what it's supposed to mean :-) – Steve Jessop Jan 02 '16 at 15:42
  • @SteveJessop Good suggestion. However, I don't want to make changes because right now Skeety is displayed as a co-author and to us, low-pointers, it's like a badge (bronze, silver, gold, skeet), hehehe. Obviously, I won't rollback if you edit. Maybe you can ask Jon to edit? (Just kidding, just kidding.) – Konrad Viltersten Jan 02 '16 at 15:52

4 Answers4

36

It's an interpolated string literal, introduced in C# 6.

It's broadly equivalent to:

eventStream.ReceiveJoke += joke =>  
    Console.WriteLine(string.Format("Pretty nice joke: {0}, Thanks!!!", joke));

The compiler looks for braces within any string literal introduced with $, and applies string formatting to it. You can use (mostly) arbitrary expressions, rather than just variables, e.g.

Console.WriteLine($"{year.State} {2000 + 16}"); // Happy 2016
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Why is it called interpolated? – ZivS Jan 01 '16 at 18:13
  • 1
    Jon, I was under the impression that string interpolation produces the same IL as an equivalent `string.Format`. Is this false? – Gusdor Jan 01 '16 at 18:15
  • 3
    @Gusdor: It depends on what you do with it. Sometimes you use it as a `FormattableString` instead, so that you can format it later or do so in the invariant culture, for example. That's why I've put that it's "broadly" equivalent, to avoid overgeneralizing :) – Jon Skeet Jan 01 '16 at 18:16
  • 1
    @FᴀʀʜᴀɴAɴᴀᴍ what is a **YAB**? – Alberto Monteiro Jan 01 '16 at 19:14
  • @FᴀʀʜᴀɴAɴᴀᴍ What's YAB? (Also, I just realized that the abbreviation of JavaScript is ambiguous... Spooky... My initials only conform to "basement floor" and "department of corrections" in my language...) – Konrad Viltersten Jan 01 '16 at 19:14
  • 2
    @KonradViltersten: I suspect it's "yet another badge" in this context. – Jon Skeet Jan 01 '16 at 19:14
  • It's also in VB.NET 14.0 (the one with VS2015). – Andrew Morton Jan 02 '16 at 16:43
24

It's the symbol that allow you to create a interpolated string, it's a new feature from C# 6, and I love it.

Also its a Syntax Sugar, I will explain what it mean in the end.

Lets see in action. look the following code

public string Receive(int value)
{
    return String.Format("Received: {0}", value);
}

public string Receive6(int value)
{
    return $"Received: {value}";
}

What happens what it is compiled

They will have the same IL implementation, look here the IL(in Debug mode, not optimized) from Receive

.method public hidebysig instance string Receive (int32 'value') cil managed 
{
    // Method begins at RVA 0x22d4
    // Code size 22 (0x16)
    .maxstack 2
    .locals init (
        [0] string
    )

    IL_0000: nop
    IL_0001: ldstr "Received: {0}"
    IL_0006: ldarg.1
    IL_0007: box [mscorlib]System.Int32
    IL_000c: call string [mscorlib]System.String::Format(string, object)
    IL_0011: stloc.0
    IL_0012: br.s IL_0014

    IL_0014: ldloc.0
    IL_0015: ret
} // end of method Program::Receive

Now lets see IL(in Debug mode, not optimized) from Receive6

.method public hidebysig instance string Receive6 (int32 'value') cil managed 
{
    // Method begins at RVA 0x22f8
    // Code size 22 (0x16)
    .maxstack 2
    .locals init (
        [0] string
    )

    IL_0000: nop
    IL_0001: ldstr "Received: {0}"
    IL_0006: ldarg.1
    IL_0007: box [mscorlib]System.Int32
    IL_000c: call string [mscorlib]System.String::Format(string, object)
    IL_0011: stloc.0
    IL_0012: br.s IL_0014

    IL_0014: ldloc.0
    IL_0015: ret
} // end of method Program::Receive6

As you can see with your own eyes, the IL is pretty much the same.

Now lets understand what is a Syntax Suggar

In computer science, syntactic sugar is syntax within a programming language that is designed to make things easier to read or to express. It makes the language "sweeter" for human use: things can be expressed more clearly, more concisely, or in an alternative style that some may prefer.

From https://en.wikipedia.org/wiki/Syntactic_sugar

So instead to write the massive string.Format, use string interpolation, the compiler will work for you and convert the syntax that you wrote, in another code, in this case, using string.Format.

Can I use formatting options like in string.Format?

Yes, you can, look below

public static string Receive(int value) 
    => string.Format("Received: {0, 15:C}", value);

public static string Receive6(int value) 
    => $"Received: {value,15:C}";

Console.WriteLine(Receive(1));
Console.WriteLine(Receive6(1));
Console.WriteLine($"Current data: {DateTime.Now: MM/dd/yyyy}")

Output (my culture is pt-br)

Received:         R$ 1,00
Received:         R$ 1,00
Current data:  01/01/2016

Obs.: I would like to mention, there is not performance difference, since using string interpolation e string.Format is exactly the same thing

Alberto Monteiro
  • 5,989
  • 2
  • 28
  • 40
8

In short, it is good way to improve the readability of the code and reduce its length. It's much better then String.Concat or + operator because string interpolation executes just one time as String.Format (and it is actually compile to String.Format method call) and you can just read the expression from left to right.

String.Format and its cousins are very versatile and useful, but their use is a little clunky and error prone. Particularly unfortunate is the use of {0} etc. placeholders in the format string, which must line up with arguments supplied separately:

var s = String.Format("{0} is {1} year{{s}} old", p.Name, p.Age);

String interpolation lets you put the expressions right in their place, by having “holes” directly in the string literal:

var s = $"{p.Name} is {p.Age} year{{s}} old";

Just as with String.Format, optional alignment and format specifiers can be given:

var s = $"{p.Name,20} is {p.Age:D3} year{{s}} old";

The contents of the holes can be pretty much any expression, including even other strings:

var s = $"{p.Name} is {p.Age} year{(p.Age == 1 ? "" : "s")} old";

Notice that the conditional expression is parenthesized, so that the : "s" doesn’t get confused with a format specifier.

Via

Community
  • 1
  • 1
Vadim Martynov
  • 8,602
  • 5
  • 31
  • 43
  • 1
    Please make it clear when you're quoting another post by using blockquotes, rather than just a link at the end of the post which doesn't make it really clear that you're simply quoting MSDN. – Jon Skeet Jan 01 '16 at 18:14
  • Why did you change my edit to make it unclear that the code in the answer was *also* just quoted from the Roslyn github page? It's simpler as it is, IMO. – Jon Skeet Jan 01 '16 at 18:38
  • Sorry it's just concurrency conflict. Also, you did the same with my first paragraph. – Vadim Martynov Jan 01 '16 at 18:46
  • What is this `{{s}}` thing? – Random832 Jan 02 '16 at 06:41
  • @Random832 since in string interpolation the { is a special character, if you want to write a { instead use it as special character, you must escape it, and the escape way is to add another {, this happens in string.Format also also. – Alberto Monteiro Jan 02 '16 at 14:21
5

This is a new feature of C# 6 that is called string interpolation, which

lets you more easily format strings. String.Format and its cousins are very versatile, but their use is somewhat clunky and error prone.

For further information about this, please have a look here.

Example

Let that we have the following class:

public class Customer
{
    public int Id { get; set; }
    public string FirstName {get; set;}
    public string LastName { get; set; }
}

and let suppose that we want to ovveride the ToString method, like below:

public override string ToString()
{
    return string.Format("The customer with Id: {0} has as FirstName: {1} and as LastName: {2}", Id, FirstName,
            LastName);
}

In C# 6 we could have the same result using string interpolation.

public override string ToString()
{
    return $"The customer with Id: {Id} has as FirstName: {FirstName} and as LastName: {LastName}";
}

Benefits of string interpolation:

  • A string is significantly easier to read than a composite string.
  • There is a reduction in the syntax errors caused by arguments following the format string that are in improper order, or missing altogether and causing an exception.
Christos
  • 53,228
  • 8
  • 76
  • 108