I just installed Visual Studio 2015 Preview on a Windows 10 tech. preview, the first thing I wanted to try out was C# 6.0.
The are a lot of videos and posts on internet about the new features of C# 6.0. The goal of this post is to test them by myself and share my impressions. I will use this post in the future as a personal reference for C# 6.0 new features.
C# 6.0 new feautures
This is the list of new features I have collected so far:
- Getter only auto properties
- Auto-Initialization of properties
- Calculated properties with body expressions
- Null conditional operators ?.
- Operator nameof()
- Strings projections
- Exceptions filters
- Await in catch and finally
- Index initializers
I wrote a small sample class that I will use as an example to test the new features.
This is the C# 5 sample class:
using System; namespace ConsoleApplication1 { public class Person { public Person(string name, int age) { if (name == null) { throw new NullReferenceException("name"); } Name = name; Age = age; Id = GetNewId(); } public string Name { get; set; } public int Id { get; private set; } public int Age { get; set; } public event EventHandler Call; protected virtual void OnCall() { EventHandler handler = Call; if (handler != null) handler(this, EventArgs.Empty); } public int GetYearOfBirth() { return DateTime.Now.Year - Age; } public JObject ToJSon() { var personAsJson = new JObject(); personAsJson["id"] = this.Id; personAsJson["name"] = this.Name; personAsJson["age"] = this.Age; return personAsJson; } #region Get new person id private static int lastId; private static int GetNewId() { lastId++; Logger.WriteInfo(string.Format("New Id = {0}", lastId)); return lastId; } #endregion } }
Applying C# 6.0 new features to a C# 5.0 class:
Now lets go throw the list of new features and apply them to our sample class:
Getter only auto properties
We can remove “private set” from read-only properties, properties with only a “setter” can be initialized only from the constructor or with auto-initialization.
public int Id { get; }
Auto-Initialization of properties
Using auto initialization we can auto initialize the Id property calling a method. It is also possible to set a default value to editable properties:
public int Id { get; } = GetNewId(); public int Age { get; set; } = 18;
Calculated properties with body expressions
It is common to have a lot of single line calculated properties or methods on our code. In lambda expressions it was already possible to write only the value to return. Now this is also possible in normal methods:
Our “GetYearOfBirth” method can be re-write like this:
public int GetYearOfBirth => DateTime.Now.Year - Age;
Note that if the method has not parameters we can also avoid the parentheses.
Null conditional operators ?.
The new ? operator check if the expression is null before continue evaluating it, this is great to clean pieces of code like
if (something != null) something.callMethod();
to
something?.callMethod();
If the operator is in an expression that should return something it returns null when the evaluation cannot continue. Events are a good example of usage for this new operator.
Let’s rewrite the OnCall method using a null conditional operator and a body expression:
protected virtual void OnCall() => Call?.Invoke(this, EventArgs.Empty);
Operator nameof()
The constructor throws an exception when the var “Name” is null. This exception has a string parameter to specify the name of the parameter that is null. The new “nameOf()” operator allows to remove this “magic” string. This helps to avoid errors during renaming re-factoring:
if (name == null) { throw new NullReferenceException(nameof(name)); }
Strings projections
String projections are an improvement of “string.Format”
It allows to rewrite the logger call:
Logger.WriteInfo("New Id = \{lastId}");
Exceptions filters and await in catch and finally
It is easier to illustrate these new features with a different example, have a look to the next piece of code:
public void RunAlarm() { try { // Run my phone alarm every morning, // if something was wrong run the backup alarm RunPhoneAlarm(); } catch (Exception) { // Run backup alarm RunBackupAlarm(); } } /// <summary> /// Run the phone alarm. /// If there is a problem with the phone and today is not Sunday -> throw an exception. /// </summary> public async void RunPhoneAlarm() { try { phone.RunAlarm(); } // New C# 6.0: catch conditions catch (Exception) if (DateTime.Now.DayOfWeek == DayOfWeek.Sunday) { Debug.WriteLine("Phone's alarm is not working... but I can fix it later..."); // New C# 6.0: await inside catch or finally block await CreateRemainder("Repair phone."); Debug.WriteLine("A remainder was created."); } }
Index initializers
This is a great feature when we have to deal with json objects in our code. We can write much easier our person.ToJson() method using index initializers. Index initializers allows to create the value to return on the fly, we can get rid of the local variable and use a body expression:
public JObject ToJSon => new JObject() {["id"] = Id, ["name"] = Name, ["age"] = Age};
–
There is also a new feature that I didn’t mention yet in this post, and the reason is that I don´t like it… but …
Using and static class
Now it is possible to add a static class in our “using” declarations and call the methods directly, for me is better to see the name of the class that implement the static method I am calling…
I prefer
Debug.WriteLine(“My message”);
Than:
using System.Diagnosis.Debug;
// 500 lines of code in between …
WriteLine(“My message”); // write where??
Conclusion
I am missing primary constructors, Microsoft didn’t mention them during the “Connect()” event. (Or I didn’t heard it…)
C# 6.0 has not big improvements but some of the new features will help to clean up our code and improve readability.
Visual Studio 2015 has some cool new features (some of them covered already by Resharper). I will test now this in deep, but that will be a different post :).
This is our class “Person” written with some C# 6.0 features:
public class Person { // Constructor public Person(string name, int age) { if (name == null) throw new NullReferenceException(nameof(name)); Name = name; Age = age; } // Events public event EventHandler Call; // Properties public string Name { get; set; } public int Id { get; } = GetNewId(); public int Age { get; set; } = 18; // Calculated Properties public int GetYearOfBirth => DateTime.Now.Year - Age; public JObject AsJSon => new JObject() {["id"] = Id, ["name"] = Name, ["age"] = Age}; #region privates private virtual void OnCall() => Call?.Invoke(this, EventArgs.Empty); private static int lastId; private static int GetNewId() { lastId++; Logger.WriteInfo("New Id = \{lastId}"); return lastId; } #endregion }