129

C# 6 brings compiler support for interpolated string literals with syntax:

var person = new { Name = "Bob" };

string s = $"Hello, {person.Name}.";

This is great for short strings, but if you want to produce a longer string must it be specified on a single line?

With other kinds of strings you can:

    var multi1 = string.Format(@"Height: {0}
Width: {1}
Background: {2}",
        height,
        width,
        background);

Or:

var multi2 = string.Format(
    "Height: {1}{0}" +
    "Width: {2}{0}" +
    "Background: {3}",
    Environment.NewLine,
    height,
    width,
    background);

I can't find a way to achieve this with string interpolation without having it all one one line:

var multi3 = $"Height: {height}{Environment.NewLine}Width: {width}{Environment.NewLine}Background: {background}";

I realise that in this case you could use \r\n in place of Environment.NewLine (less portable), or pull it out to a local, but there will be cases where you can't reduce it below one line without losing semantic strength.

Is it simply the case that string interpolation should not be used for long strings?

Should we just string using StringBuilder for longer strings?

var multi4 = new StringBuilder()
    .AppendFormat("Width: {0}", width).AppendLine()
    .AppendFormat("Height: {0}", height).AppendLine()
    .AppendFormat("Background: {0}", background).AppendLine()
    .ToString();

Or is there something more elegant?

Drew Noakes
  • 300,895
  • 165
  • 679
  • 742
  • 7
    http://stackoverflow.com/questions/31764898/long-string-interpolation-lines-in-c6 – Ric Oct 20 '15 at 12:26
  • @DmytroShevchenko, I did consider doing so. However I wasn't sure about accepting yours as I watched you copy/paste the [top voted answer](http://stackoverflow.com/a/31764920/24874) from the link that Ric posted, then edit it to look different. That all happened within 5 minutes so the edits aren't visible. Your answer is technically correct, but I felt like you should have given credit. I would actually like to accept Ric's comment, but that's not possible. – Drew Noakes Oct 21 '15 at 14:45
  • @DrewNoakes your question has been marked as a duplicate of the question linked by Ric. Ric was the one who marked it, too. So there's no need to add yet another instance of that link to my answer. If you disagree, I would appreciate your reasoning. And of course I edited the code in my answer. Although, the reason was not to make it look different, but rather to match the example in your question. – Dmytro Shevchenko Oct 21 '15 at 14:59
  • @DmytroShevchenko see the site's footer: user contributions licensed under cc by-sa 3.0 with attribution required – Drew Noakes Oct 21 '15 at 15:06
  • @DrewNoakes Ha! That is a good argument! :) Edited my answer. – Dmytro Shevchenko Oct 21 '15 at 15:09
  • 3
    Voting to reopen. The supposed duplicate question asks something different and contrary (they want line breaks in source code but not the string). Moderators, read questions carefully before you close them! – Colonel Panic May 05 '16 at 14:50

4 Answers4

269

You can combine string interpolation $ and verbatim literal @ together to get a multiline interpolated string literal:

string s =
$@"Height: {height}
Width: {width}
Background: {background}";

Source: Long string interpolation lines in C#6 (Thanks to @Ric for finding the thread!)

Vinod Srivastav
  • 3,644
  • 1
  • 27
  • 40
Dmytro Shevchenko
  • 33,431
  • 6
  • 51
  • 67
  • 9
    I had tried this as @$ (reversed) and it didn't work so I figured they couldn't be combined. It didn't occur to me to try it the other way. – kencordero Feb 15 '17 at 15:37
  • 9
    Starting with C# 8.0, you can use the $ and @ tokens in any order: both $@"..." and @$"..." are valid interpolated verbatim strings. In earlier C# versions, the $ token must appear before the @ token. – hal9000 Mar 24 '20 at 15:30
  • Amazingly, that won't work if there are escape characters in the string, for example: `` – dpant Dec 04 '22 at 09:44
  • @dpant One way to resolve is to define the character as `char c = '"'` and do `$@""` – Vinod Srivastav Apr 15 '23 at 07:54
13

I'd probably use a combination

var builder = new StringBuilder()
    .AppendLine($"Width: {width}")
    .AppendLine($"Height: {height}")
    .AppendLine($"Background: {background}");
thehennyy
  • 4,020
  • 1
  • 22
  • 31
sara
  • 3,521
  • 14
  • 34
  • could the downvoter give any insights? I don't see any issues with this, is there a problem? – sara Oct 20 '15 at 12:56
  • For the record I actually upvoted you. There may be cases where this is more readable. The only negative I can think of is that it's creating a few extra objects for the GC. – Drew Noakes Oct 21 '15 at 14:52
  • 3
    I think that is only a negative in exceptional cases where you have very limited resources or need to append thousands, if not millions of rows. I don't particularly like verbatim strings for formatting. It makes the layout of the text in the code file responsible for the appearance of the output. I prefer stringbuilder, it's more expressive. – sara Oct 21 '15 at 15:50
  • I agree about the formatting of verbatim strings being a bit ugly. `String.Concat` might also be an option here. – Drew Noakes Oct 21 '15 at 23:03
  • Definitely like concat more than verbatim. The nice thing about stringbuilder is that it takes care of doing linebreaks for you. I'd probably be OK with either one though. – sara Oct 22 '15 at 08:16
  • @sara I think your comment about using verbatim strings for formatting makes the layout of the text in the code file responsible for the appearance of the output." is a really great point! It made me rethink the approach I was about take on formatting a multiline string. I think maybe if you included that statement in your answer, it might have made down-voters consider why they were actually down voting instead of just not liking the answer or thinking that it didn't answer the OPs specific question (which it did) instead of answering the "spirit" of the question && emphasising code quality. – Adam Porad Oct 09 '19 at 18:09
  • they might have downvoted this since it doesn't produce a formattable string, for example it can't be used in `ExecuteSqlInterpolated` – Patrick Beynio Dec 02 '20 at 12:42
  • Performance of interpolated strings seems to be very good, much better than StringBuilder. – cskwg Mar 12 '21 at 07:03
13

Since C# 11 you can do it like this (file multiline.cs):

using System;
public class Program
{
    public static void Main()
    {
        var multiLineStr =
            $$"""
            {
                "Color" : "Blue",
                "Thickness" : {{1 + 1}}
            }
            """;
        Console.WriteLine(multiLineStr);
    }
}

Now the string variable multiLineStr contains:

{
    "Color" : "Blue",
    "Thickness" : 2
}

Explanation:

  • The string is now delimited by """, and interpolation is delimited by {{ and }} because there were two consecutive $ specified (you can add more $ or " if needed, but for the quotes you must use the same number for opening and closing it).

  • The indentation of the lines where you define the starting and ending quotes matters! If you indented it with different amount of tabs and/or spaces, the compiler might complain.

  • If required, you can have more than 3 quotes, e.g. """"". Please note that the number of opening and closing quotes must match (in this case, 5 opening and 5 closing double quotes are required to enclose a string).

  • With this new syntax, the @ prefix is not needed because you don't need to escape double quotes inside of the string any more

This simplifies declaring multi-line strings a lot.

You can find a full documentation here @ Microsoft.


Note: You can try it out in LinqPad 7 (in Preferences -> Query tab, make sure that "Enable C#/F# preview features" is enabled), in Visual Studio or on the command line. DotNetFiddle does not support the new syntax (yet). To try it out on the command line, use the batch file CompileCS you can find in the link and invoke it like: compilecs /run multiline.cs (provided you have installed a recent version of Roslyn).

Matt
  • 25,467
  • 18
  • 120
  • 187
  • I fixed the method to match the output you provided. I suppose there was a copy paste indentation mistake. Are non-static `Main` and `Dump` methods LinqPad specifics? I adjusted it to become "usual" C# code, in this case the LinqPad note may be removed. – Ray Aug 12 '22 at 15:33
  • @syroot - Thanks for fixing the formatting. In LinqPad you just write `void Main() { ... }`. And `.Dump(Title)` is an extension method which you append to any variable or expression. It prints the object into the results window. If you are curious, [here](https://stackoverflow.com/a/12006038/1016343) you can find more about LinqPad extensions. – Matt Nov 03 '22 at 13:46
  • 1
    Note: you do not have to use double dollar and braces. Singles are just fine, unless you need some `{}` inside your string. – C-F Jan 27 '23 at 05:34
  • @C-F That's right, it is not mandatory generally, but in the example I gave you it is - there you need them to escape the `{ ... }` by writing `{{ ... }}` – Matt Jan 27 '23 at 07:09
8

Personally, I just add another interpolated string using string concatenation

For example

var multi  = $"Height     : {height}{Environment.NewLine}" +
             $"Width      : {width}{Environment.NewLine}" +
             $"Background : {background}";

I find that is easier to format and read.

This will have additional overhead compared to using $@" " but only in the most performance critical applications will this be noticeable. In memory string operations are extremely cheap compared to data I/O. Reading a single variable from the db will take hundreds of times longer in most cases.

Andrew Monteith
  • 117
  • 1
  • 3