1. Initializers for auto-properties
You can now initialize a property, just as you can in a field:
public class Customer
{
public string First { get; set; } = "Jane";
public string Last { get; set; } = "Doe";
}
The property will be read only when the setter is left out.
public class Customer
{
public string First { get; } = "Jane";
public string Last { get; } = "Doe";
}
Read only properties can be assigned in the type’s constructor,
public class Customer
{
public string Name { get; };
public Customer(string first, string last)
{
Name = first + " " + last;
}
}
2. Using static
The feature allows the static members of a type to be imported, making them available without qualification in code:
using static System.Console;
using static System.Math;
using static System.DayOfWeek;
class Program
{
static void Main()
{
WriteLine(Sqrt(3*3 + 4*4));
WriteLine(Friday - Monday);
}
}
This is helpful when you have a set of functions in a class that you frequently use. System.Math is a good example of this.
This also lets you access named values of an enum type, like the System.DayOfWeek members above.
3. String interpolation
String.Format is useful but clumsy. Those {0} etc. placeholders in the format string must line up with the other arguments.
var s = String.Format("{0} is {1} year{{s}} old", p.Name, p.Age);
String interpolation puts the expressions in their right place.
var s = $"{p.Name} is {p.Age} year{{s}} old";
Alignment and format specifiers can be supplied.
var s = $"{p.Name,20} is {p.Age:D3} year{{s}} old";
The expressions can even contain other strings.
var s = $"{p.Name} is {p.Age} year{(p.Age == 1 ? "" : "s")} old";
4. nameof expressions
Occasionally you need the name of a variable or property. When throwing an ArgumentNullException you may want to name the guilty argument.
if (x == null) throw new ArgumentNullException(nameof(x));
You can use more elaborate names, but only the final identifier will be used.
WriteLine(nameof(person.Address.ZipCode)); // prints "ZipCode"
5. Index initializers
Object and collection initializers are concise way to provide initial values. Initializing dictionaries and other objects with indexers was less graceful. Here is the new syntax to set values to keys through an indexer:
var numbers = new Dictionary<int, string> {
[7] = "seven",
[9] = "nine",
[13] = "thirteen"
};
6. Null-conditional operators
The null-conditional operator (?) lets you access members only when they are not null. Else a null result is returned.
int? length = customers?.Length; // null if customers is null
Customer first = customers?[0]; // null if customers is null
The null-conditional operator is conveniently used with the null coalescing operator (??):
int length = customers?.Length ?? 0; // 0 if customers is null
Null-conditional operators can be chained, if there is a need to check for null more than once:
int? first = customers?[0].Orders?.Count();