The new C# 6.0 null-conditional operator is a handy vehicle for writing more concise and less convoluted code. Assuming one has an array of customers, then you could get null instead of a length if customers
is null using this (examples from MSDN):
int? length = customers?.Length;
Similarly you could get null instead of a customer with this:
Customer first = customers?[0];
And for a more elaborate expression, this yields null if customers
is null, the first customer is null, or the first customer's Orders
object is null:
int? count = customers?[0]?.Orders?.Count();
But then there is the interesting case of the non-existent customer that the null-conditional operator does not seem to address. We saw above that a null customer is covered, i.e. if an entry in the customers
array is null. But that is quite distinct from a non-existent customer, e.g. looking for customer 5
in a 3-element array or customer n
in a 0-element list. (Note that the same discussion applies to Dictionary lookup as well.)
It seems to me that the null-conditional operator is focused exclusively on negating the effects of a NullReferenceException; IndexOutOfRangeException or KeyNotFoundException are alone, exposed, cowering in the corner, and needing to fend for themselves! I submit, that in the spirit of the null-conditional operator, it should be able to handle those cases as well... which leads to my question.
Did I miss it? Does the null-conditional provide any elegant way to truly cover this expression...
customers?[0]?.Orders?.Count();
...when there is no zeroth element?
No, because it is a null-conditional operator, not an indexoutofrange-conditional operator and is merely syntactic sugar to something like the following:
int? count = customers?[0]?.Orders?.Count();
if (customers != null && customers[0] != null && customers[0].Orders != null)
{
int count = customers[0].Orders.Count();
}
You can see that if there is no zeroth customer, you will get your regular IndexOutOfRangeException
.
One way you could work around it is to have an extension method that checks for the index and returns null if it doesn't exist:
public static Customer? GetCustomer(this List<Customer> customers, int index)
{
return customers.ElementAtOrDefault(index); // using System.Linq
}
Then your check could be:
int? count = customers?.GetCustomer(0)?.Orders?.Count();