As part of Visual Studio 15.3, Microsoft offered their first point release of C#, since .NET 1.1. C# 7.1 offers three new features, two of which work.

Default Literals C# 7.1/7.2

The idea behind default literals is to remove a bit of boilerplate code. Here’s a common example:

public Task<Order> GetOrderAsync(int orderKey, CancellationToken token = default(CancellationToken))

That’s somewhat verbose, so copying Visual Basic’s Nothing keyword, you can now write this:

public Task<Order> GetOrderAsync(int orderKey, CancellationToken token = default)

And this works as expected. The problem comes when you use a nullable value type.

public Task<Order> GetOrders(int? limit = default)

This should set the limit parameter to null, but in C# 7.1 it actually returns a 0.

The fix for this issue is scheduled for C# 7.2, which will be released alongside Visual Studio 15.5.

Infer Tuple Names C# 7.1

Since the introduction of anonymous types, C# has been able to implicitly name properties. For example, if you write the below line then the object y will have properties named A and B.

var y = new { x.A, x.B };

With C# 7.1, value tuples gain that ability as well.

var z1 = (A: x.A, B: x.B); //explicit names var z2 = (x.A, x.B); //inferred names

Check out our previous coverage for more on tuple name inference.

Async Main C# 7.1

There isn’t much to say here. Main functions can now be asynchronous, which removes a bit of boilerplate code that would have otherwise need to be written.

Conditional Ref C# 7.2

C#’s Conditional operator is often referred to as “the ternary operator” because it’s the only one in the language. With C# 7.2, we’ll be getting a second ternary operator called the Conditional Ref operator.

This minor feature will allow ref expressions to be used in conditionals. Here is an example from the proposal:

ref var r = ref (arr != null ? ref arr[0]: ref otherArr[0]);

Note that in addition to using the ref keyword next to the two possible results, you also need the ref keyword and parens around the entire expression.

Leading Separator C# 7.2

This feature extends the ability to use underscores in numeric literals. The following is quoted from the proposal:

123 // permitted in C# 1.0 and later 1_2_3 // permitted in C# 7.0 and later 0x1_2_3 // permitted in C# 7.0 and later 0b101 // binary literals added in C# 7.0 0b1_0_1 // permitted in C# 7.0 and later // in C# 7.2, _ is permitted after the `0x` or `0b` 0x_1_2 // permitted in C# 7.2 and later 0b_1_0_1 // permitted in C# 7.2 and later

Non-trailing Named Arguments C# 7.2

Named arguments service two purposes in C#:

Allows skipping of optional parameters

Providers clarity, especially for Boolean arguments

This feature deals with the second. To illustrate:

void DoSomething(bool delayExecution, bool continueOnError, int maxRecords); DoSomething(true, false, 100);

Unless you have memorized the function signature, it is hard to tell at a glance what true and false apply to. In the past you could write this:

DoSomething(delayExecution: true, continueOnError: false, maxRecords: 100);

But it seems odd to need to specify maxRecords when that parameter wasn’t in doubt. Under the Non-trailing Named Arguments proposal, you can specify just the parameters you want.

DoSomething(delayExecution: true, continueOnError: false, 100);

Editor’s note: Enums are still better than Booleans when clarity is an issue.

Private Protected C# 7.2

In C# there are five accessibility levels: private, internal, protected, protected-or-internal, and public. But in the CLR there’s a sixth accessibility level called FamANDAssem, “accessible by sub-types only in this assembly”.

Trivia: In the CLR, “protected” is called “family” and “internal” is called “assembly”.

With the new keyword “private protected”, developers gain the ability to use the CLR’s FamANDAssem flag. The Private Protected proposal explains why this is important:

There are many circumstances in which an API contains members that are only intended to be implemented and used by subclasses contained in the assembly that provides the type. While the CLR provides an accessibility level for that purpose, it is not available in C#. Consequently API owners are forced to either use internal protection and self-discipline or a custom analyzer, or to use protected with additional documentation explaining that, while the member appears in the public documentation for the type, it is not intended to be part of the public API. For examples of the latter, see members of Roslyn's CSharpCompilationOptions whose names start with Common.

Readonly References C# 7.2

We’ve covered readonly references before so there’s nothing new to say here. They are essentially just a way to indicate that you want the performance benefits of passing structs by reference, but not the ability to actually modify the value.

Currently this readonly references proposal is marked as prototyped but not implemented.

Compile time enforcement of safety for ref-like types [7.2 Proposal]

This C# feature is also known as “interior pointer” or “ref-like types”. The proposal is to allow the compiler to require that certain types such as Span<T> only appear on the stack. Important only for high performance scenarios, the ref-like types proposal hasn’t changed since we last reported on it.

Dropped Features

These features are no longer marked as part of the 7.2 proposal. That doesn’t mean they won’t happen, but they probably won’t happen soon.