Tuesday, 12 September 2017
Andy Clymer
10 minute read
This last month, I have at last started my first new real C# 6 project. While the features have not been earth shattering, they are actually a joy to use and certainly do help to clean up a fair amount of boiler plate code. After string interpolation I have found the null conditional operator (?.
) aka the Elvis operator to be the most helpful, as it removes those often ugly if not null checks. Historically, I have removed allot of null checks using the Null Pattern:
public abstract class Logger
{
public static Logger NullLogger = new NullLogger();
public abstract void Log(string message);
}
public class NullLogger : Logger
{
public override void Log(string message) {
return;
}
}
public class ConsoleLogger : Logger
{
public override void Log(string message){
Console.WriteLine(message);
}
}
...
static void Main(string[] args)
{
Logger logger = Logger.NullLogger;
DoIt(logger);
}
private static void DoIt(Logger logger)
{
logger.Log("Starting");
....
}
Making the logger assignment inside Main
to be Logger.NullLogger
as opposed to just null allows the code to work with out a null check.
C#6 ?.
Elvis operator removes the need for the null pattern as we can simply make the call, removing the need for the NullLogger
class instance:
private static void DoIt(Logger logger)
{
logger?.Log("Starting");
}
What makes the ?.
Elvis operator even more compelling is that you can chain them one after another, especially useful in LINQ to XML processing. The following code won’t throw a null reference exception even though the Address
and Street
element is missing from the XML:
private static void Main(string[] args)
{
var person = new XElement("Person",
new XElement("Name", "Andy"),
new XElement("Address",
new XElement("Street", "Redwing")));
var personWithNoAddress = new XElement("Person");
Console.WriteLine(person?.Element("Address") ?.Element("Street"));
Console.WriteLine(personWithNoAddress?.Element("Address")?.Element("Street"));
}
Most of what has been written above is well known, what is perhaps slightly less well known is that you can also use the technique to remove the need for null checking when invoking an event. Historically, we have seen event invocation written as follows:
public class Clock
{
public event EventHandler Tick;
protected virtual void OnTick()
{
// non thread safe version
if (Tick != null)
{
Tick(this, EventArgs.Empty);
}
// thread safe version
var localTick = Tick;
if (localTick != null)
{
localTick(this, EventArgs.Empty);
}
}
}
We can now indeed use the ?.
Elvis operator here too, the compiler emits the same code as the thread safe version in the above example.
protected virtual void OnTick()
{
Tick?.Invoke(this, EventArgs.Empty);
}
I can’t say I’m a fan of this as we lose the simplification of the event invocation we have had since .NET 1.0. So for me its back to the good old Null pattern for thread safe event invocation.
public class Clock
{
public event EventHandler Tick = delegate { };
protected virtual void OnTick()
{
Tick(this,EventArgs.Empty);
}
}
This technique for me is by far the cleanest, and easiest to read. So the Elvis operator will certainly not be universally adopted in my code.
While writing this article it also got me thinking where else does the compiler protect you from NullReferenceException
. One place I found was the using statement:
public class LazyLogger : Logger, IDisposable
{
private readonly string filename;
private StreamWriter output;
public LazyLogger(string filename)
{
this.filename = filename;
}
public override void Log(string msg)
{
output = output ?? new StreamWriter(filename);
output.Write(msg);
}
public void Dispose()
{
using(output);
}
}
Clearly now you would use ?.
, which provides a far more clear intent but interesting to see this has been around for a while.
So to sum up I would strongly recommend keeping in mind the new features of C#6 as you plough through building another class, in the style of C#<6 and have a quick think could I make this more readable and cleaner with C#6.
Last updated: Monday, 12 June 2023
Director
Andy is a Director at Rock Solid Knowledge.
We're proud to be a Certified B Corporation, meeting the highest standards of social and environmental impact.
+44 333 939 8119