10

Looking for some best-practice guidance. Let's say I have a line of code like this:

Color color = someOrder.Customer.LastOrder.Product.Color;

where Customer, LastOrder, Product, and Color could be null under normal conditions. I'd like color to be null if any one of the objects in the path is null, however; in order to avoid null reference exceptions, I'd need to check for the null condition for each one of the objects, e.g.

Color color = someOrder == null ||
              someOrder.Customer == null || 
              someOrder.Customer.LastOrder == null ||
              someOrder.Customer.Product == null ? 
              null : someOrder.Customer.LastOrder.Product.Color;

or I could do this

Color color = null;
try {color = someOrder.Customer.LastOrder.Product.Color}
catch (NullReferenceException) {}

The first method clearly works, but it seems a bit more tedious to code and harder to read. The second way is a bit easier but probably not a good idea to use exception handling for this.

Is there another shortcut way of checking for nulls and assigning null to color if necessary? Or any thoughts on how to avoid NullReferenceExceptions when using such nested references?

Eren Ersönmez
  • 38,383
  • 7
  • 71
  • 92

6 Answers6

14

You are looking for the null-safe dereferencing operator.

Color color = someOrder?.Customer?.LastOrder?.Product?.Color;

Unfortunately C# doesn't support it. Maybe it will be added later, but there are no plans to do that at the moment.

Related

Community
  • 1
  • 1
Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
  • As noted in the 'Related' link above, the Null-conditional operators ?. and ?[] were added with C# 6 (aprox July 2015) – Rich K Nov 15 '21 at 14:05
2

Best practice is to follow Law of Demeter which sounds as: don't talk to strangers. I.e. object should avoid invoking methods of a member object returned by another method. This allows to write less coupled, more maintainable and readable code.

So, avoid using 'train wrecks' like someOrder.Customer.LastOrder.Product.Color, because they completely violate Law of Demeter. It's even hard to understand what business meaning this code has. Why are you getting color of product of some other order, which is not the current one?

Possible way to remove train wreck - push functionality closer to interesting end of wreck. In your case, also consider passing last product to your method, instead of using some order.

Sergey Berezovskiy
  • 232,247
  • 41
  • 429
  • 459
  • Thank you. I'll take a look at LoD. By the way, the code was just an example I made up - no business meaning. – Eren Ersönmez Apr 28 '12 at 10:29
  • 1
    I like that someone said this even though it doesn't DIRECTLY answer the question. There's no question that you have to write complex code to make sure you don't end up trying to use a null reference in code like that. While it is important that you know the technical answer, including what C# is capable of and is not, this kind of code should scare you into looking at your overall design. – Chris Gomez Sep 22 '14 at 23:11
1

where you need to achieve this do this.

Usage

Color color = someOrder.ComplexGet(x => x.Customer.LastOrder.Product.Color);

or

Color color = Complex.Get(() => someOrder.Customer.LastOrder.Product.Color);

Helper Class Implementation

public static class Complex
{
    public static T1 ComplexGet<T1, T2>(this T2 root, Func<T2, T1> func)
    {
        return Get(() => func(root));
    }

    public static T Get<T>(Func<T> func)
    {
        try
        {
            return func();
        }
        catch (Exception)
        {
            return default(T);
        }
    }
}
Jay Byford-Rew
  • 5,736
  • 1
  • 35
  • 36
0

I would definitely prefer the first method... the second one exploits the exception mechanism for program flow which is bad practice IMHO...

AFAIK there is no shortcut or "null-safe dereferencing operator" in C# .

Yahia
  • 69,653
  • 9
  • 115
  • 144
0

Define unique method for accessing nested properties. For example like this

private Customoer GetCustomer(Order order)
{
  return order != null ? order.Customer : null;
}

private Order GetLastOrder(Customer customer)
{
   return customer != null ? customer.LastOrder : null;
}

Using the defined method access your properties across the application

Thiru kumaran
  • 1,262
  • 1
  • 10
  • 10
0

You can also use the Null-conditional operator in an if statement. Really useful if there is a lot of nested values.

Example:

public class DummyDto
{
    public string Name { get; set; }

    public DummyDto Parent { get; set; }
}

class Program
{
    static void Main(string[] args)
    {

        var dummyDto = new DummyDto();

        //Both if statements will be true below
        if(dummyDto.Parent?.Name == null)
        {
            Console.WriteLine("DummyDto is null");
        }

        if (dummyDto.Parent == null || dummyDto.Parent.Name == null)
        {
            Console.WriteLine("DummyDto is null");
        }
    }
}
Ogglas
  • 62,132
  • 37
  • 328
  • 418