Resolving null values in C#
January 31, 2017 1 Comment
Say you have a method which accepts a string parameter. The method may need to handle null values in some way. One strategy is to validate the parameter and throw an exception:
private static string Resolve(string input) { if (input == null) throw new ArgumentNullException("Input"); . . . }
Another strategy is to provide some default value with an if-else statement:
private static string Resolve(string input) { string res; if (input == null) { res = "Empty input string"; } else { res = input; } return res; }
This can be greatly simplified with the ternary operator:
private static string Resolve(string input) { string res = input == null ? "Empty input string" : input; return res; }
An even simpler solution is by using the null-coalescing operator ?? :
private static string Resolve(string input) { string res = input ?? "Empty input string"; return res; }
This statement is equal to the first if-else solution but it’s a lot more elegant and concise.
You can use this technique with any nullable type of course, not just strings. The ?? operator can even be chained:
private static string Resolve(string input) { string intermediate = null; string res = input ?? intermediate ?? "Empty input string"; return res; }
Here res will be “Empty input string” if both ‘input’ and ‘intermediate’ are null. If ‘input’ is null and ‘intermediate’ is ‘hello world’ then ‘res’ will be ‘hello world’.
In C# 6
C# 6 has a new syntax for testing for null values. Let’s build an object model from the ground up:
- The Address object has a street name and a street number
- The Workplace object has an Address
- The Person object has a Workplace
- The Person object is retrieved from a web service within a GetPersonResponse object
So it’s a relatively deep structure. Here are the relevant classes:
public class Address { public string Street { get; } public int Number { get; } public Address(string street, int number) { Street = street; Number = number; } } public class Workplace { public Address Address { get; } public Workplace(Address address) { Address = address; } } public class Person { public Workplace Workplace { get; } public Person(Workplace workplace) { Workplace = workplace; } } public class GetPersonResponse { public Person Person { get; } public GetPersonResponse(Person person) { Person = person; } }
Now imagine that after acquiring the response from the web service we want to print the Person’s work address. You may be tempted to rush ahead and write:
Console.WriteLine(getPersonResponse.Person.Workplace.Address.Street);
This code can potentially throw the dreaded NullReferenceException for any nullable object:
- getPersonResponse
- Person
- Workplace
- Address
- Street
E.g. if the Person is unemployed then Workplace may be null depending on the business rules we allow:
GetPersonResponse getPersonResponse = new GetPersonResponse(new Person(null)); Console.WriteLine(getPersonResponse.Person.Workplace.Address.Street);
To fully guard against null objects you have to validate each component in the object chain:
if (getPersonResponse != null && getPersonResponse.Person != null && getPersonResponse.Person.Workplace != null && getPersonResponse.Person.Workplace.Address != null && getPersonResponse.Person.Workplace.Address.Street != null) { Console.WriteLine(getPersonResponse.Person.Workplace.Address.Street); } else { Console.WriteLine("No work address available"); }
You’ll probably agree that it is an unhealthy amount of code for a simple task.
C# 6 has a neat shorthand solution for that, here you are:
if (getPersonResponse?.Person?.Workplace?.Address?.Street != null) { Console.WriteLine(getPersonResponse.Person.Workplace.Address.Street); }
Here’s a test object:
GetPersonResponse getPersonResponse = new GetPersonResponse(new Person(new Workplace(new Address("Heaven street", 78))));
Sure enough, the work address “Heaven street” will be printed on the console window.
View all various C# language feature related posts here.
Andras, thank you for sharing and great job making this easily understandable. However, my brain stuttered a bit in the very last example when I wondered to myself, “why isn’t the null case handled like it is in the long-form example?”.
I believe you meant to have an else statement on there to fully flesh out the example.