Here’s an overview of the features offered by C# 7.0, C# 7.1, and C# 7.2 – comparing them to previous versions of C#: digit separators, binary literals, expression-bodied members, out var, tuples, pattern matching, and more!
References to the chapter numbers for more information references Professional C# 7 and .NET Core 2.0.
The digit separators make the code more readable. You can add _ to separate numbers when declaring variables. The compiler just removes the _. The following code snippet looks a lot more readable with C# 7. C# 7.2 allows to put the separator at the beginning:
More information on digit separators in chapter 2, Core C#!
C# 7 offers a new literal for binaries. Binaries can only have values 0 and 1. Now the digit separator becomes really important:
More information on binary literals in chapter 2, Core C#!
C# 6 allows expression-bodied methods and properties. With C# 7, expression bodies can be used with constructors, destructors, local functions, property accessors and more. Here you can see the difference with property accessors between C# 6 and C# 7:
More information on expression-bodied members in chapter 3, Objects and Types!
Previous to C# 7, out variables had to be declared before its use. With C# 7, the code is reduced by one line, as the variable can be declared on use:
More information on out var in chapter 3, Objects and Types!
Non-trailing Named Arguments
C# supports named arguments that are required with optional arguments, but can support readability in any cases. With C# 7.2, non-trailing named arguments are supported. Argument names can be added to any argument with C# 7.2:
More information on named arguments in chapter 3, Objects and Types!
Structures should be read-only (with some exceptions). Using C# 7.2 it’s possible to declare the struct with the readonly modifier, so the compiler verifies that the struct is not changed. This guarantee can also be used by the compiler to not copy a struct passing it as a parameter, but instead passing a reference:
More information on readonly struct in chapter 3, Objects and Types!
C# 7.2 also allows the in modifier with parameters. This guarantees that a passed value type is not changed, and it can be passed by reference to avoid a copy:
ref, in, and out modifiers are covered in chapter 3, Objects and Types!
C# 7.2 adds a new access modifier:
private protected. The access modifier
protected internal allows access to the member if it’s used from a type in the same assembly, or from a type from another assembly that derives from the class. With
private protected it’s an AND instead of an OR – access is only allowed if the class derives from the base class and is in the same assembly.
Access modifiers are covered in chapter 4, Object Oriented Programming with C#!
With C# 7.1, a default literal is defined which allows a shorter syntax compared to the default operator. The default operator always requires the repetition of the type which is now not needed anymore. This is practical with complex types:
The default literal is covered in chapter 5, Generics!
Previously to C# 7 it was not possible to declare a function within a method. You could create a lambda expression, and invoke this one as shown here in the C# 6 code snippet. With C# 7, a local function can be declared within a method – the local function is only accessible within the scope of the method:
Local functions are explained in chapter 13, Functional Programming!
Tuples allow combining objects of different types. Previous to C# 7, tuples have been part of the .NET Framework with the
Tuple class. The members of the tuple can be accessed with
Item3… Using C# 7, tuples are part of the language, and you can define the names of the members:
Other than that, the new tuples are value types (ValueTuple) whereas the Tuple type is a reference type. All the changes with tuples are covered in chapter 13, “Functional Programming”.
Inferred Tuple Names
C# 7.1 extends tuples by automatically inferring tuple names, similar to anonymous types. With C# 7.0, the members of the tuple always need to be named. In case the tuple member should have the same name as the property or field you assign to it, with C# 7.1, if the name is not supplied, it has the same name as the assigned member:
Inferred tuple names are covered in chapter 13, Functional Programming.
No, this is not a typo. Deconstructors are not destructors. A tuple can be deconstructed to separate variables, such as shown in the following code snippet. It’s also possible to deconstruct a Person object – if a Deconstruct method is defined:
Deconstruction is covered in chapter 13, Functional Programming.
With pattern matching, the is operator and the switch statement have been enhanced with three kinds of patterns: the const pattern, the type pattern, and the var pattern. The following code snippet shows patters with the is operator. The first check for a match matches the constant 42, the second match a Person object, and the third match every object with the var pattern. Using the type and the var pattern, a variable can be declared for strongly typed access. Using the switch statement, you can use the same patterns with the case clause. You can also declare a variable to be strongly typed in case the pattern matches. You can also use when to filter the pattern on a condition:
Pattern matching is covered in chapter 13, Functional Programming.
Throwing exceptions was only possible with a statement, but not in an expression. Thus, receiving a parameter with a constructor, extra checks had for null were necessary to throw an ArgumentNullException. With C# 7, exceptions can be thrown in expressions, thus it is possible to throw the ArgumentNullException when the left side is null – using the coalescing operator.
Throw expressions are covered in chapter 14, Errors and Exceptions.
Before C# 7.1, the Main method always needs to be declared of type void. With C# 7.1, the Main method can also be of type Task and use the async and await keywords:
Asynchronous programming is covered in chapter 15, Asynchronous Programming.
.NET Core has a big focus on enhancing the performance. With additions to the reference semantics. Previous to C# 7, the ref keyword could be used with parameters, to pass value types by reference. Now it’s also possible to use the
ref keyword with the return type and with local variables.
The following code snippet shows some of the features on ref semantics.
- The method
GetNumberto return a reference to an
int. This way, the caller has direct access to the element in the array, and can change its content.
- With C# 7.2, the
readonlymodifier can be added to ref returns. This way the caller can’t change the content of the returned value, but still reference semantics is used, a copy of the value type when returning the result can be avoided. The caller receives a reference but isn’t allowed to change it.
- Previous to C# 7.2, C# allows to create reference types (a class), and value types (a struct). However, the struct can also be stored on the heap when boxing takes place. With C# 7.2, a type can be declared that is only allowed on the stack: ref struct:
The new features for references are covered in Chapter 17, Managed and Unmanaged Memory.
C# 7.x offers many, many, many new practical features. I hope you enjoyed the short summary. All these (among many other topics on .NET Core, ASP.NET Core, and Windows apps) are covered in detail my new book Professional C# 7 and .NET Core 2.0.
Enjoy creating code and my new book,