Now almost fifteen years old, C# continues to improve with each major release. If you use any version of Visual C# 2015, you have access to C# 6.0 and its many new features. I’ve chosen to focus on five of the most important or useful ones.
Null-Conditional Operator
I rate this as probably the most important new feature. Every C# programmer has probably experienced a Null-reference exception at some point, usually by forgetting to new a reference variable. For instance:
[csharp]
var List<String> list;
…
list.Clear(); // it’s null then bam!
[/csharp]
A compiler generally won’t allow that sort of thing to go through; but if it did, it would produce an exception along the lines of, “Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object.”
It’s customary to check that the reference variable is not null before passing parameters to a method:
[csharp]
void CheckList(List<String list){
// other stuff
if (list != null){
list.Clear();
}
}
[/csharp]
The new to C# 6.0 Null Conditional operator ?. does the “if” for you:
[csharp]
void CheckList(List<String list){
// other stuff
list?.Clear();
}
[/csharp]
if it’s null, it doesn’t call list.Clear(). You can chain multiple ?. For example, here’s how the result of a method might be called:
[csharp]
if (p.GetData()?.ProcessDataOK()?==true) {
// do something.
}
[/csharp]
This reminds me very much of optionals in Swift, as does this example:
[csharp]
using static System.Console;
internal class Program
{
private static string StopCompilerObjecting()
{
return null;
}
private static void Main(string[] args)
{
String s= StopCompilerObjecting(); // assign a null
var p = s.Length;
WriteLine( p );
}
}
[/csharp]
The StopCompilerObjecting() is a way to assign a null to a string without a compiler error. Running this generates a null-reference exception, as you’d expect. You may wonder why there’s no Console; prefixing the WriteLine( p ); in a new twist, you can now use the word static in using clauses, negating the need for Console.
As an experiment, change the second line in the Main() body to:
[csharp]
var p=s?.Length;
[/csharp]
It outputs nothing, not even an exception! Behind the scenes, I guess it’s checking HasValue. How do I know this? Because Intellisense shows HasValue and Value. In other words, s?.Length returns an Int?, not an Int. Remember that; it’s bound to come up as an interview question.
Auto Initializing Properties
Prior to C# 6.0, when you used properties, you could initialize them only when creating an instance by calling the constructor, or explicitly assigned in the constructor. Now you can assign a default value where the property is defined.
Here’s an example of the old way. As Make only has a get; it’s read-only:
[csharp]
using static System.Console;
internal class Program
{
private static void Main(string[] args)
{
var Car = new AutoMobile();
WriteLine($"Make: {Car.Make} Model: {Car.Model}");
}
public class AutoMobile
{
public string Make { get; }
public string Model { get; set; }
public AutoMobile()
{
Make = "Car Company";
Model = "Basic Model";s
}
}
}
[csharp]
(An additional note: I’ve used another new C# 6.0 feature. Instead of placeholders in the WriteLine statement—it would have been Console.WriteLine("Make: {0} Model: {1}",car.Make,Car.Model)—the $"" notation has the string interpolated, i.e. it calls String.Format() behind the scenes. The values in the curly braces are evaluated. Note you can’t use verbatim (@ prefixed) strings with string interpolation. <a href="https://msdn.microsoft.com/en-GB/library/dn961160.aspx">Here are some more details</a> on string interpolation.)
By using auto property initializers, there’s no longer a need for the constructor for the properties. Here’s the class AutoMobile now:
[csharp]
public class AutoMobile
{
public string Make { get; } = "Car Company";
public string Model { get; set; } = "Basic Model";
}
[/csharp]
If you do use a constructor, you can now assign to a read-only property in the constructor body, as well.
Expression Based Functions and Properties
These tie in with the auto property initializers, using a Lambda function (i.e., an anonymous function), called in the usual way by the fat arrow =>, to provide a value. The example below rolls Ten x Six side dice:
[csharp]
public static int RollaDice(int x) => (int) r.Next(x) + 1;
public static Random r = new Random();
private static void Main(string[] args)
{
for (var i = 0; i < 10; i++)
{
WriteLine(Dice(6));
}
}
[/csharp]
RollaDice() is only static because I’m calling it from main; Random r is likewise static, but I only ever want one instance of a random number generator, so I always declare it static, even in an instance of a class.
The statement version of this lets you run a single statement. If ErrorObj is an instance of some logging class, then this logs an error:
[csharp]
public void LogError(string msg) => ErrorObj.WriteLine(msg);
[/csharp]
Plus you can use it to provide a value for a property.
Exception Filters
In the catch (ExceptionType) of a try..catch statement, you can now add when(bool condition) to the catch to add extra granularity to exception handling. This rather contrived example lets you decide whether the exception from a divide by zero is suppressed or reported:
[csharp]
using System;
using static System.Console;
internal class Program
{
public static int TryDivByZero(int denominator,bool allow=false)
{
try
{
return 4 / (denominator – 1);
}
catch (DivideByZeroException) when (allow)
{
return 0;
}
catch (Exception)
{
WriteLine("Divide by zero error");
return -1;
}
}
private static void Main(string[] args)
{
var res=TryDivByZero(1,true);
WriteLine(res);
}
}
[/csharp]
When allow is true, it silently returns 0; otherwise it says Divide by Zero error and returns -1.
New line breaks in Strings
While some might see this as a trivial addition, it can be quite handy in decluttering long string assignments:
[csharp]
private static void Main(string[] args)
{
var longstring = @"Hello
World";
WriteLine(longstring);
}
[/csharp]
You can break strings across lines, but they have to be verbatim strings i.e. @ prefixed strings. Watch out for those spaces or tabs now, because they’re included in the string, as well. The output from running this is:
[csharp]
Hello
World
[/csharp]
Conclusion
Yes, many of the features new in C# 6.0 are syntactic sugar, but don’t underestimate them; reducing the source size and eliminating boilerplate makes the code easier to read and understand. This is also the first C# to use Roslyn, the compiler technology that gives you access to the compilation process. Want to see what’s in the works for C# 7.0? Watch the design notes page on Github and use the C# 7.0 filter.
What, no mention of the nameof operator? There are a lot of interesting developments with C# 6.0, not least of which is a crazy FAST compiler, rewritten “accidentally” in F#. The nameof operator is hands down one of the most useful things I think I would use. There are other compelling features too, but nameof saves a lot of time diving deep into reflection when just to find a property, method, or other name.