Software Development

C# 6 features

Luty 17, 2016 1
Podziel się:

Changes presented in C# 6.0 are not particularly exceptional, however, the main goal in this version was to simplify your code, so most of the new features are intended to provide more intuitive syntax.
All new features of C# 6 require the C# 6.0 compiler but it’s important to notice that all of them don’t require any specific version .NET Framework – because all features are implemented in the compiler and don’t depend on .NET Framework.

Auto-property initializers

Prior to C# 6 for initializing immutable properties we had to use private readonly fields. This solution ensures proper access to those properties but with many properties there is lot of irrelevant code lines. The other way was to create properties with private setter however it makes properties mutable for methods within the class. C# 6 introduce new feature to solve that issue in a simple way – we can declare a property with only getter and initialize it in the constructor.
Furthermore C# 6 allows to initialize properties directly within their declaration, the same way as fields. Initializers can be any expression (but not using this).

Example:

public class A
{
	public string X { get; } = "valueOfX";
	public DateTime StartDay { get; } = DateTime.Today;
}

Null-Conditional Operator
Every .NET developer knows the NullReferenceException which is usually result of not sufficient null checking before invoking a member on that object. Let’s consider this example:

if (personList != null)
{
	Person first = personList[0];
	int count = personList.Count;            
}

The null checking is required, otherwise the NullReferenceException would be thrown. C# 6 allows to write it much more simple with new feature.

Person first = personList?[0];  // null if customers is null
int? nullableCount = personList?.Count; // null if customers is null
int count = personList?.Count ?? 0; // 0 if customers is null

The null-conditional operator returns null for null-value.
But what happens when the null-conditional operator appears within a call chain? Consider the example:

var dob = person?.DateOfBirth?.ToString();

It seems that since person?.DateOfBirth? just returns null there should be a NullReferenceException thrown, but this situation is handled with the language behavior that returns null immediately, without attempting execution further instruction, with no exceptions. This is a concept known as null-propagation.
What about a data type for the result of null-conditional? For example a data type for someValue?.Length – we can’t use int. Attempting to assign it to int will results with compile error. In that case really handy are nullable types.

int? length = person?.Name?.Length;

But we can also use the null-coallescing operator at the end of expression:
var count = post?.Tags?.Count ?? 0;

int length = person?.Name?.Length ?? 0; 

Expression Bodied Methods and Auto-Properties

Expression bodied functions and auto-properties are implemented with an expression following the function declaration instead of statement body. To assign the expression use the arrow operator (=>). This simplified implementation can be used for methods with or without parameters. The same way we can implement read-only (getter only) properties – called expression bodied properties.

public TimeSpan Age => DateTime.Now – DateOfBirth;
public override string ToString() => string.Format("{0} is {1} old.", Name, Age);

Dictionary initializers

Prior to C# 6.0 the common method for initializing and filling Dictionary includes the {key, value} syntax. This is easy to implement for simple objects but when we have more complex object with nested structures might be not very clear and it’s easy to lose track of all those curly brackets.
In C# 6 there is an improvement of dictionary assignment, using index-based syntax. The data types of key-value pairs are corresponding to the types declared for the dictionary.

var peopleDict = new Dictionary<string, Person>;
{
	["mike"] = new Person("Mike Smith", 28),
	["lilly"] = new Person("Lilly Potter", 25)
};


String Interpolation

To display strings combined in one composite string we used string.Format() method. Probably any .NET developer struggled with that when there are many strings to put together. This is not easy to read or validate. The placeholders and parameters must be in proper order.

string.Format("{0} {1} was born {2} and now is {3}.", FirstName, LastName, DateOfBirth, Age);

In C# 6 there is new alternative approach to composite formatting. The result of string.Format() we can obtain using string literal prefixed with a “$” and each argument within curly brackets.

$"{FirstName} {LastName} was born {DateOfBirth} and now is {Age}.";

The string interpolation syntax prevent from disordered or missing arguments errors. Compiler transforms it into string.Format() so in effect there are no changes (eg. Localization). That means also that we can use options from original method defining format of an argument or use an expression.

string s = $"It is now {DateTime.Now:d} at {DateTime.Now:t}";

Using static

Another feature simplifying C# code is using static. Prior to C# 6 there was possible to use only namespaces in the using directive but with this feature you can use type of static class. Therefore you can gain access to static members of type without prefix of the type name – you can invoke them directly.

//prior to C# 6
var result = Math.Sqrt(Math.Abs(x) * Math.Pow(y, 2) + z * Math.PI);
//C# 6
var result = Sqrt(Abs(x) * Pow(y, 2) + z * PI);

With using static you can restrict access to extension methods to single class unlike using namespace – when all of extension methods from this namespace are available.
Enums can also be called that way. It is very useful if the names of enum items are understandable and clear without type prefix.

using static System.ConsoleKey;
	//…
	switch (keypressed)
	{
		case A:
			break;
		case B:
			break;
	}

What about aliases to namespace? For example char – to use this type it’s required to write full namespace, in this case System.Char.

using static char; //Error
using static System.Char; //Correct

Be careful with using static though – in situation when you specify using static for types that have a member with the same name – to distinguish them it’s required to add prefix of the type name while invoking them.

using static System.IO.Directory;
using static System.IO.File;
	//…
	if (!Exists(filename)) // ERROR: The call is ambiguous between the following methods or properties: 'Directory.Exists(string)' and 'File.Exists(string)'
	{
		throw new ArgumentException("The file does not exist.", nameof(filename));
	}

This feature was added to simplifying your code and make it more readable, but when the context is not obvious and using static could lead to confusion you probably shouldn’t use it. It’s best to limit number of the using static directives to just a few classes which you use frequently.

The nameof Operator

As the name of this feature suggests – operator nameof returns the name of any item like class, method, property or parameter. When the fully qualified identifier is passed as parameter to nameof() it will return just the final identifier (last part). This feature protects from runtime errors caused by misspellings and also works with renaming tools. nameof(someFancyParameterName) will return someFancyParameterName.

Exception Improvements

Prior to C# 6 the exception filtering was only possible on the type level but now there was introduced the “when” clause to do more accurate filtering for exceptions. After a catch() you can now add an extra condition.

try
{
	throw new Exception("My exception");
}
catch (Exception ex) when (ex.Message == "My exception")
{
	Console.WriteLine("My exception caught");
}
catch (Exception ex) 
{
	Console.WriteLine("Other exception caught here");
}
5 / 5
Tagi: ,

Imię i nazwisko (wymagane)

Adres email (wymagane)

Temat

Treść wiadomości

komentarze(1)

avatar'
PKK
18 marca 2016 Odpowiedz

Very nice, especially string and "$" ;)

Zostaw komentarz