Raw and Verbatim Strings

Verbatim strings keep backslashes; raw string literals hold quotes and newlines with no escaping, which suits JSON, SQL and regex.

Syntax@"verbatim text" """raw text""" $"""raw text with {value}"""

In an ordinary string literal the backslash is special. It starts an escape sequence: \n means a newline, \t a tab, \" a quote. That is useful until the text you want actually contains backslashes or quotes, at which point the literal fills up with doubled characters and becomes hard to read and easy to get wrong.

Verbatim strings

Put @ before the opening quote and escape sequences are switched off. @"C:\logs\app.log" is the path as written, and the literal may span several lines. One thing is still special: to include a quote you write it twice, as in @"say ""hi""".

Raw string literals

Added in C# 11, a raw string literal starts and ends with at least three double quotes. Nothing inside is special at all, including quotes. If the content itself has three quotes in a row, use four delimiters instead, and so on.

The multi-line form has rules worth learning precisely. The opening quotes must be the last non-whitespace characters on their line. The closing quotes must be the first non-whitespace characters on theirs. Whatever whitespace sits to the left of the closing quotes is removed from every line, so the literal can be indented with the surrounding code without that indentation landing in the string. The newline before the closing quotes is not part of the string.

What trips people up

Prefix $ for interpolation: $"""...""". Use $$"""...""" when the content needs literal braces, as JSON does, and then interpolations take double braces.

Example

Example · csharp
// A plain literal: \\ means one backslash.
string escaped = "C:\\logs\\app.log";

// Verbatim: @ switches escape sequences off, so backslashes are literal.
string verbatim = @"C:\logs\app.log";

// Raw: three or more quotes. Nothing inside is special, not even a quote.
string raw = """C:\logs\app.log""";

Console.WriteLine(escaped);
Console.WriteLine(verbatim);
Console.WriteLine(raw);
Console.WriteLine(escaped == raw);

// Multi-line raw. The whitespace left of the closing """ is removed from every
// line, so this JSON starts at column 0 inside the string.
string json = """
    {
      "name": "ada",
      "tags": ["a", "b"]
    }
    """;

Console.WriteLine(json);

// Output:
// C:\logs\app.log
// C:\logs\app.log
// C:\logs\app.log
// True
// {
//   "name": "ada",
//   "tags": ["a", "b"]
// }

When to use it

  • Embed a Windows file path or a registry key in source without doubling every backslash.
  • Keep a multi-line SQL query readable in a repository class.
  • Write an expected JSON response inside a test without escaping quotes.
  • Store a regular expression exactly as it was typed into a pattern tester.

More examples

SQL kept readable in source

Query text copied out of a database tool pastes in unchanged, keeps its line breaks, and can hold single and double quotes without edits. The // lang=sql comment above the literal tells the editor to colour and check it as SQL. Note that the value here is written into the query text only to keep the example self-contained; real queries pass values as parameters, never by pasting them into the string.

Example · csharp
// lang=sql
string sql = """
    SELECT id, name
    FROM users
    WHERE active = true
      AND name = 'ada'
    ORDER BY name
    """;

Console.WriteLine(sql);

// Output:
// SELECT id, name
// FROM users
// WHERE active = true
//   AND name = 'ada'
// ORDER BY name

Interpolating into raw JSON with $$

This is how a request body or a configuration fragment gets written in a test without escaping anything. The number of dollar signs sets how many braces an interpolation takes, so you can always pick a count that leaves the document's own braces alone. For real payloads prefer a serializer over hand-built JSON; this form is for fixtures and expected values in tests.

Example · csharp
int id = 7;
string name = "ada";

// One $ would make every brace an interpolation, and JSON is full of braces.
// Two $ mean an interpolation needs two braces; a single brace is literal.
string body = $$"""
    {
      "id": {{id}},
      "name": "{{name}}"
    }
    """;

Console.WriteLine(body);

// Output:
// {
//   "id": 7,
//   "name": "ada"
// }

Regular expressions without doubled backslashes

All three literals produce exactly the same 13-character pattern; only the source spelling differs. Regex patterns are the classic case for @ or raw literals, because a pattern written with doubled backslashes is almost impossible to review. Raw literals have the edge when the pattern also contains double quotes.

Example · csharp
using System.Text.RegularExpressions;

// In a plain literal every backslash has to be doubled.
string plain = "^\\d{3}-\\d{4}$";

// @ keeps the backslashes as written.
string verbatim = @"^\d{3}-\d{4}$";

// A raw literal needs no escaping either, and pastes straight from a tester.
string raw = """^\d{3}-\d{4}$""";

Console.WriteLine(plain == verbatim);
Console.WriteLine(verbatim == raw);
Console.WriteLine(Regex.IsMatch("555-0199", raw));
Console.WriteLine(Regex.IsMatch("5550199", raw));

// Output:
// True
// True
// True
// False

Discussion

  • Be the first to comment on this lesson.