[c#] Line continue character in C#

We have a unit test with variable that contains a very long string.

Question is how to write this in code, without having problems with line breaks or that the code is difficult to read.

In VB there is a line continue character, is there an equivilant in C#?

This question is related to c#

The answer is


If you declared different variables then use following simple method:

Int salary=2000;

String abc="I Love Pakistan";

Double pi=3.14;

Console.Writeline=salary+"/n"+abc+"/n"+pi;
Console.readkey();

You can use verbatim literals:

const string test = @"Test
123
456
";

But the indentation of the 1st line is tricky/ugly.


You must use one of the following ways:

    string s = @"loooooooooooooooooooooooong loooooong
                  long long long";

string s = "loooooooooong loooong" +
           " long long" ;

String Constants

Just use the + operator and break the string up into human-readable lines. The compiler will pick up that the strings are constant and concatenate them at compile time. See the MSDN C# Programming Guide here.

e.g.

const string myVeryLongString = 
    "This is the opening paragraph of my long string. " +
    "Which is split over multiple lines to improve code readability, " +
    "but is in fact, just one long string.";

IL_0003: ldstr "This is the opening paragraph of my long string. Which is split over multiple lines to improve code readability, but is in fact, just one long string."

String Variables

Note that when using string interpolation to substitute values into your string, that the $ character needs to precede each line where a substitution needs to be made:

var interpolatedString = 
    "This line has no substitutions. " +
    $" This line uses {count} widgets, and " +
    $" {CountFoos()} foos were found.";

However, this has the negative performance consequence of multiple calls to string.Format and eventual concatenation of the strings (marked with ***)

IL_002E:  ldstr       "This line has no substitutions. "
IL_0033:  ldstr       " This line uses {0} widgets, and "
IL_0038:  ldloc.0     // count
IL_0039:  box         System.Int32
IL_003E:  call        System.String.Format ***
IL_0043:  ldstr       " {0} foos were found."
IL_0048:  ldloc.1     // CountFoos
IL_0049:  callvirt    System.Func<System.Int32>.Invoke
IL_004E:  box         System.Int32
IL_0053:  call        System.String.Format ***
IL_0058:  call        System.String.Concat ***

Although you could either use $@ to provide a single string and avoid the performance issues, unless the whitespace is placed inside {} (which looks odd, IMO), this has the same issue as Neil Knight's answer, as it will include any whitespace in the line breakdowns:

var interpolatedString = $@"When breaking up strings with `@` it introduces
    <- [newLine and whitespace here!] each time I break the string.
    <- [More whitespace] {CountFoos()} foos were found.";

The injected whitespace is easy to spot:

IL_002E:  ldstr       "When breaking up strings with `@` it introduces
    <- [newLine and whitespace here!] each time I break the string.
    <- [More whitespace] {0} foos were found."

An alternative is to revert to string.Format. Here, the formatting string is a single constant as per my initial answer:

const string longFormatString = 
    "This is the opening paragraph of my long string with {0} chars. " +
    "Which is split over multiple lines to improve code readability, " +
    "but is in fact, just one long string with {1} widgets.";

And then evaluated as such:

string.Format(longFormatString, longFormatString.Length, CountWidgets());

However this can still be tricky to maintain given the potential separation between the formatting string and the substitution tokens.


@"string here
that is long you mean"

But be careful, because

@"string here
           and space before this text
     means the space is also a part of the string"

It also escapes things in the string

@"c:\\folder" // c:\\folder
@"c:\folder" // c:\folder
"c:\\folder" // c:\folder

Related


In his excellent answer, StuartLC cites an answer to a related question and mentions that placing newlines inside the {expression} of an interpolated string "looks odd." Most would agree, but the unpleasant source code effect can be mitigated somewhat--and without any runtime consequences--by using dedicated {expression} blocks which resolve to default(String), that is, null (and specifically not String.Empty).

The (albeit minor) point is to not mess-up or pollute your actual expression content, by instead using a dedicated token for this purpose. So if you declare a constant, for example:

const String more = null;

...then a line which might be too long to look at in source code, such as...

var s1 = $"one: {99 + 1} two: {99 + 2} three: {99 + 3} four: {99 + 4} five: {99 + 5} six: {99 + 6}";

...can be instead written like this.

var s2 = $@"{more
    }one: {99 + 1} {more
    }two: {99 + 2} {more
    }three: {99 + 3} {more
    }four: {99 + 4} {more
    }five: {99 + 5} {more
    }six: {99 + 6}";

Or perhaps you prefer a different "odd" approach to the same thing:

// elsewhere:
public const String ? = null;  // Unicode '\u039E', Greek 'Capital Letter Xi'

// anywhere:
var s3 = $@"{
           ?}one: {99 + 1} {
           ?}two: {99 + 2} {
           ?}three: {99 + 3} {
           ?}four: {99 + 4} {
           ?}five: {99 + 5} {
           ?}six: {99 + 6}";

Actually, it looks like we can also do it without a continuation symbol:

var s4 = $@"one: {99 + 1
            }two: {99 + 2
            }three: {99 + 3
            }four: {99 + 4
            }five: {99 + 5
            }six: {99 + 6}";

All four examples produce the same string at runtime, which in this case is all on a single line:

one: 100 two: 101 three: 102 four: 103 five: 104 six: 105

As Stuart suggested, IL performance is preserved in both these examples by not using + to concatenate strings. Although the longer format string in my new example is indeed stored in the IL, and thus your executable, the null placeholders it references are not initialized, and there are no excess concatenations or function calls at runtime. For comparison, here is the IL for the above two examples.

IL for first example

ldstr "one: {0} two: {1} three: {2} four: {3} five: {4} six: {5}"
ldc.i4.6
newarr object
dup
ldc.i4.0
ldc.i4.s 100
box int32
stelem.ref
dup
ldc.i4.1
ldc.i4.s 101
box int32
stelem.ref
dup
ldc.i4.2
ldc.i4.s 102
box int32
stelem.ref
dup
ldc.i4.3
ldc.i4.s 103
box int32
stelem.ref
dup
ldc.i4.4
ldc.i4.s 104
box int32
stelem.ref
dup
ldc.i4.5
ldc.i4.s 105
box int32
stelem.ref
call string string::Format(string, object[])

IL for second example

ldstr "{0}one: {1} {2}two: {3} {4}three: {5} {6}four: {7} {8}five: {9} {10}six: {11}"
ldc.i4.s 12
newarr object
dup
ldc.i4.1
ldc.i4.s 100
box int32
stelem.ref
dup
ldc.i4.3
ldc.i4.s 101
box int32
stelem.ref
dup
ldc.i4.5
ldc.i4.s 102
box int32
stelem.ref
dup
ldc.i4.7
ldc.i4.s 103
box int32
stelem.ref
dup
ldc.i4.s 9
ldc.i4.s 104
box int32
stelem.ref
dup
ldc.i4.s 11
ldc.i4.s 105
box int32
stelem.ref
call string string::Format(string, object[])