c# / .net
.NET 7, and the string literal I stopped escaping

.NET 7 was released on the eighth of November with C# 11. I have written before about .NET 6 making small services simpler; this release continues in the same direction, and three of the language additions are worth the upgrade on their own.
Raw string literals
Every C# codebase I have worked in contains a test with JSON in it, and that JSON is unreadable:
var expected = "{\"name\":\"Probe\",\"limits\":{\"memory\":\"256Mi\"}}";
Nobody reads that. People stop checking whether it is correct and start checking
whether it compiles. Verbatim strings help with the quotes and then break the
moment the content contains a " of its own.
C# 11 allows a literal delimited by three or more quotes, which ends the escaping entirely:
var expected = """
{
"name": "Probe",
"limits": { "memory": "256Mi" }
}
""";
The closing delimiter sets the indentation: whatever whitespace precedes it is stripped from every line, so the literal stays aligned with the code around it without carrying that alignment into the value. If the content itself contains three quotes, use four as the delimiter.
This is a keystroke feature that turns into a correctness feature, because escaped JSON in a test is a thing people stop reading, and things people stop reading stop being checked.
Required members
The other one I have adopted immediately:
public sealed class ServiceOptions
{
public required string Name { get; init; }
public required Uri Endpoint { get; init; }
public int Retries { get; init; } = 3;
}
required means the compiler will not let an object initialiser omit that
property. Not a runtime check, not a guard clause in a constructor, not a nullable
annotation that only produces a warning — the initialiser will not compile.
This closes a specific and irritating gap. Object initialisers have always been the pleasant way to construct configuration-shaped objects, and they have always been the way to accidentally forget a property. The previous answer was a constructor with eight parameters, which is worse to read and worse to extend. Now the pleasant syntax and the enforced one are the same syntax.
Adding a required property to an existing type is a source-breaking change for
everyone constructing it, which is the intended behaviour and worth knowing before
you add one to a public type.
List patterns
Pattern matching learned to look at sequences:
var result = segments switch
{
["health"] => Health(),
["v1", "members", var id] => Member(id),
["v1", "members", var id, .. var rest] => MemberSub(id, rest),
_ => NotFound(),
};
The .. is a slice pattern and it can bind. I find this genuinely clearer than
the equivalent chain of length checks and index lookups, which is the sort of code
where off-by-one bugs live.
I would use it for parsing and dispatch and not much else. A switch over shapes
is readable at four cases and not at fourteen.
The runtime side, and the number I would not quote
.NET 7 also brings a large amount of performance work and continued investment in Native AOT — compiling to a native executable with no JIT, which means faster startup and a smaller footprint.
Native AOT is the one I am most interested in and least ready to make claims about. The reasons it matters are the ones I care about in containers: a process that starts faster is a process that scales out faster, and a smaller image is a cheaper deployment. But the published figures come from the workloads that were measured, and everything I have written about measuring a container's memory still applies. The constraints are real too — reflection-heavy code and runtime code generation do not survive the trip, which rules out a good deal of what a typical ASP.NET application does.
So my summary of the release is that the language changes are safe to adopt on Monday and the runtime changes are worth an experiment with your own workload. That has been true of the last three .NET releases, and it is a much better place to be than the years when an upgrade was a project.
Tagged
Written by
Deyan Peev
Founding Engineer · Sofia, Bulgaria


