Hi community,
it has been a very busy start of the year for me, but here I am as usual sharing with you information that you might find useful. Today’s post is about the internals of a couple new features available in C# 6. The new version of the language introduces the following features and more information can be found on Roslyn site on Codeplex:
- Compiler as a Service (Roslyn)
- Import of static type members into namespace
- Exception filters
- Await in catch/finally blocks
- Auto property initializers
- Default values for getter-only properties
- Expression-bodied members
- Null propagator (Succinct null checking)
- String interpolation
- nameof operator
- Dictionary initializer
On this post, however, I will talk about string interpolation and null propagation. Let’s get started with string interpolation which can be defined as “In computer programming, string interpolation or variable interpolation (also variable substitution or variable expansion) is the process of evaluating a string literal containing one or more placeholders, yielding a result in which the placeholders are replaced with their corresponding values”. This has been around for a long time now in C/C++ and almost any language but always through explicitly invoking a function and passing in the expected parameters, a good example of this would be the printf function. To illustrate this better the following code snippet in C++ and its output (something similar can be achieved with std:: ostream:: operator << which is not in scope for this article).
#include "stdafx.h"
#include "stdio.h"
#include "conio.h"
int main() {
for (auto start = 'a'; start < 123; start++)
printf("Selected ASCII character %c in uppercase is %c (code: %i)\n", start, start - 32, start);
_getch();
return 0;
}
In C# we usually accomplish the same thing by calling the string.Format function, as shown below
Enumerable.Range(0, 7).Select(p => p * 1).ToList().ForEach(q => Trace.WriteLine(string.Format("{0} is {1}{2} day of the week",
new object[] { (DayOfWeek)q, q + 1, (q == 0 ? "st" : q == 1 ? "nd" : q == 2 ? "rd" : "th") })));
And the output is
So what happens when we use string interpolation in our C# code? To illustrate this, we will refactor our previous code snippet to use “interpolation”
Enumerable.Range(0, 7).Select(p => p * 1).ToList()
.ForEach(q => Trace.WriteLine($"{(DayOfWeek)q} is {q + 1}{(q == 0 ? "st" : q == 1 ? "nd" : q == 2 ? "rd" : "th")} day of the week"));
The output is the same, but you must be wondering why? The answer to that question can be found in the generated MSIL (depicted below). Yes, the same function is called so by prefixing a string with $ (dollar sign) we indicate the C# compiler that string needs to be interpolated, but in reality it’s a wrapper to call the same function (string.Format).
Now, let’s look at the second feature to discuss on this article – “null propagation”. If you’ve been developing software with .NET (or with any other language that uses pointers or passes information by reference… Yes, everything in .NET is a pointer) pretty much) it’s very likely that you might have seen the pesky “null reference exception” (C0000005 – Access Violation) is nothing but a memory that cannot be read/written (e.g.: An object that has not been yet initialized). In the past before, C# 6 we had to check for nullability (if object != null then do something). Those days are in the past though, with the new null-propagation operator “we’re covered”, let’s take the following code snippet for example
public partial class Form1 : Form {
protected Invoice CurrentInvoice {
get; set;
}
public Form1() {
InitializeComponent();
CurrentInvoice = new Invoice();
}
private void button3_Click(object sender, EventArgs e) {
CurrentInvoice.AddItem(Guid.NewGuid().ToString(), 10);
}
private void Form1_Load(object sender, EventArgs e) {
CurrentInvoice.OnReachedThreshold += (a, b) => listBox1.Items.Add(((Invoice)a).InvoiceId);
}
}
public class Invoice {
public string InvoiceId {
get; set;
}
public int ItemCountThreshold {
get; private set;
}
protected Dictionary<Guid, KeyValuePair<string, decimal>> Items {
get;
private set;
}
public decimal Total {
get {
return Items.Values.Sum(p => p.Value);
}
}
public event EventHandler OnReachedThreshold;
public void AddItem(string description, decimal value) {
Items.Add(Guid.NewGuid(), new KeyValuePair<string, decimal>(description, value));
if (Items.Count == 5)
OnReachedThreshold?.Invoke(this, new EventArgs()); // Using null-propagation operator instead of checking for nullability myself
}
public Invoice() {
InvoiceId = $"Invoice:{Guid.NewGuid()} - Created:{DateTime.Now}";
Items = new Dictionary<Guid, KeyValuePair<string, decimal>>();
}
public Invoice(int threshold = 5) : this() {
ItemCountThreshold = threshold;
}
}
There’s an event that fires to notify the UI about a threshold being reached, if this event didn’t have any object subscribed it will definitely throw a NullReferenceException because the delegate hasn’t been set, but C# 6.0 once again makes it easy for developers and takes care of that, as shown in the following MSIL (you can find the codes here)
The nullability check is taken care of by the compiler, but once again the generated MSIL is pretty much the same as if we had done the check ourselves.
Happy coding,
Angel