Click here to Skip to main content
15,881,750 members
Articles / Programming Languages / C# 5.0

Emulating the Safe Navigation Operator in C#

Rate me:
Please Sign up or sign in to vote.
4.60/5 (8 votes)
20 Nov 2014CPOL11 min read 17.7K   78   9   11
The safe navigation operator could prove to be a nifty feature when it eventually makes it into C#. It's included in the planned upcoming release of C# 6. Until then, you may need to emulate it.

Introduction

Would you want to write safe, clean and maintainable code while accessing objects composed within other objects? The safe navigation operator can come to your rescue. But, it's not in C# yet. In this article, I shall share with you my way of emulating it.

Background

The safe navigation operator is available in a few other languages, for example the Groovy language:

Java
String lname = person.name?.ToLowerCase();

The operator ?. allows you to safely call the method ToLowerCase on the member name of the person object. 'Safely' means without throwing a NullReferenceException even when the name member is null. It will allow you to safely chain method calls when accessing a deep hierarchy of objects.

A closer look at the problem

Consider the following somewhat contrived example (in C#):

C#
class A
{
  public B b;
}

class B
{
  public C c;
}

class C
{
  public string name;
}

and we have an object of class A assigned to a variable a:

C#
var a = new A() { b = new B() }

The above expression creates an object of class A with its b member set to a newly instantiated object of class B. However, the c member of the object referenced by b is set to the default value null, because it's not explicitly assigned any value. Now let's say somewhere later in the program, we wish to refer to the name member of the c object 'inside' the b object inside the a object using this expression:

C#
a.b.c.name

This will surely fail at run time with the NullReferenceException because the member c is null. We need to resort to the following conditional expression using the ternary operator ?:

C#
(a != null && a.b != null && a.b.c != null ? a.b.c.name : null)

This not only looks clunky and but is also error prone. It becomes worse when the class members involved are methods and not variables. I will give a pragmatic example. The other day I was using the XElement class for processing an XML file. The relevant part of the file is shown here:

XML
<family>
  <person gender="female">
    ...
  </person>
  <person>
    ...
  </person>
</family>

The relevant part of my C# code was:

C#
if (person.Attribute("gender").Value == "male")
{
  ... // do something with the male members of the family
}

The code did its job correctly with the first person element in the XML shown above, but crashes with a NullReferenceException at runtime when it tries to process the second element. Why? There's no gender attribute on the second element, and there's no check for it in the code. The safe way of coding would have been:

C#
if (person.Attribute("gender") != null 
&& person.Attribute("gender").Value == "male")
{
    ...
}

This is only an example to show the cumbersome approach one has to resort to writing safe code - one has to repeat the call to the Attribute method. In this specific case, the .NET API provides a type-specific cast that makes it convenient to write the same code in less verbose way. But, I digress. Had the current version of C# been endowed with the safe navigation operator, the same code could be rewritten like this:

C#
if (person.Attribute("gender")?.Value == "male")
{
    ...
}

Having extolled the virtues of the safe navigation operator, and the fact that it's missing in the current versions of C# (version 5 and below), is there a possibility of emulating it. Yes, we can! In fact, the approach I will use below even surpasses the convenience offered by the safe navigation operator.

The Solution

Define an extension method as shown below:

C#
static class Utils
{
  public static Tresult NotNull<Tin, Tresult>(this Tin a, Func<Tin, Tresult> whenNotNull)
  {
    return a != null ? whenNotNull(a) : default(Tresult);
  }
}

As you can see, the extension method is housed inside a static class (as required by the compiler) which I have called Utils. The extension method, by definition is static so that it can be called without needing to instantiate the Utils class. Also, buried inside the definition just before the first angle bracket ('<') is the name of the method - 'NotNull'. The name is not very descriptive, but I couldn't find a more concise and expressive one. It's this method that emulates the functionality of the safe navigation operator. The method is a generic one that takes a couple of type parameters, called Tin and Tresult. Tin is the type of object on which the method will be called as denoted by the method parameter a. Note that the this keyword appearing before the declaration of a in the parameter list is what makes this method an extension method. This is as per the rules of an defining extension method and has nothing to do with the topic under discussion. And now, the interesting part: the second parameter is a delegate of the .NET type System.Func<Tin, Tresult>. This means I can pass any delegate that 'points' to a method takes a single parameter of type Tin and returns an object of type Tresult. It's the same return type as that of the NotNull method.

The body of the NotNull method itself is a one-liner. We check whether a is not null and if so return the same object returned by the method pointed by the delegate parameter. If that's not the case (that is, if a is null), we return the default value of type Tresult. This default value is null for reference (class) types and 'empty' value for value types. In a later section, I will show you how to modify the above solution to take into account a custom-made value to return in case of a being null. Alright, enough of explanation, we shall now see the NotNull method in action. Seeing the demo will also help clarify this wordy explanation.

Let's apply the method to the XML reading problem discussed a few paragraphs before. We rewrite the code:

C#
if (person.Attribute("gender").NotNull(x => x.Value) == "male")
{
  ...
}

If you look closely at the code above, you will see that the NotNull method is being called on the object of type Xattribute (the return type of the Attribute method). Comparing with the definition of the NotNull method, we see that this is the Tin parameter. The Tin type parameter is XAttribute in this specific case. The parameter a of the NotNull method is of type Xattribute. Next, I have used a lambda expression to pass an anonymous method to the delegate parameter of the NotNull method. All the anonymous method does is return the Value member of the XAttribute object. Can you tell what's the return type of the NotNull method? That's the same return type as that of the anonymous method which is System.String. You can double-check this by the type of the Value member being returned by the anonymous method above. They are the same. As you can see, the NotNull method doubles up as a safety check against null reference. If the XAttribute object returned by the Attribute method is null, the delegate is never invoked. And, in that case the value returned by the NotNull method will be the default value of XAttribute type, which is null. It's this null that's checked for equality with the string "male". Now, doesn't that code look elegant. There's no repetition of the Attribute method call; it's readable and safe.

We shall now go back to the contrived example discussed at the beginning of this article. The example consisted of a set of three classes, A, B and C. We were trying to access the name member using an object of class A. Here's the equivalent solution using the NotNull method:

C#
a.NotNull(x => x.b).NotNull(x => x.c).NotNull(x => x.name)

In the expression above, the first invocation of NotNull, the type of object returned is B; the second invocation results in object of type C and the last invocation results in object of type System.String (the type of member name). What do you think, isn't this technique nifty?

Surpassing the power of the safe navigation operator

I mentioned that the approach I will be showing you will even surpass the convenience of the safe navigation operator. Now, I will make good that claim. Specifically, I will be targeting the 'short-coming' of the NotNull method in that it's only able to return a default instance of type 'Tresult'. To address this, let me introduce another overload of the NotNull method:

C#
public static Tresult NotNull<Tin, Tresult>
(this Tin a, Func<Tin, Tresult> whenNotNull, Func<Tresult> whenNull)
{
  return a != null ? whenNotNull(a) : whenNull();
}

This overload of NotNull method takes 3 parameters. The first two parameters are identical to that in the first overload, while the third parameter is the one that gives special powers to the method making it surpass the safe navigation operator in terms of the convenience offered. This third parameter is also a delegate, but of the standard .NET type System.Func<Tresult> that 'points' to a method that takes no parameter and returns an object of type Tresult. The only other part that's changed from the first overload is the body of the method. We are now returning the object returned from the method pointed by the second delegate parameter. To distinguish this parameter from the first delegate parameter, I have tried to come up with descriptive names for both. Finally, I settled on calling the first delegate parameter by the name whenNotNull and the second delegate as whenNull. Depending on whether the value of a parameter is null, I return the result of invoking one or the other delegate. Again, let's see this overload of NotNull method in action.

The complete Utils class, including the second overload of NotNull method, now looks like this:

C#
static class Utils
{
  public static Tresult NotNull<Tin, Tresult>
    (this Tin a, Func<Tin, Tresult> whenNotNull) // the first overload
  {
    return a != null ? whenNotNull(a) : default(Tresult);
  }

  public static Tresult NotNull<Tin, Tresult>(this Tin a, Func<Tin, 
  Tresult> whenNotNull, Func<Tresult> whenNull) // the second overload
  {
    return a != null ? whenNotNull(a) : whenNull();
  }
}

In the XML processing code example, what if I wanted to express the fact that a missing gender attribute on a person element implies that the person is a male. To clarify things, if I have the following XML:

XML
<person gender="female">
  ...
</person>
<person>
  ...
</person>

implies that the second person element has the attribute gender set to "male". To express this succintly using our NotNull methods, I would rewrite the C# code as below:

C#
if (person.Attribute("gender").NotNull
(x => x.Value, () => "male") == "male")
{
  ...
}

Now, isn't that code looking elegant and expressive? The code invokes the second overload of the NotNull method - the one that takes 3 parameters. Particularly, I pass a delegate to the whenNull parameter that points to an anonymous method. The anonymous method takes no parameters and all it does is return the string "male". This delegate gets invoked when processing the second person element in the XML file. Since the element has no gender attribute, the C# expression person.Attribute("gender") is null. When the NotNull method is invoked, its a parameter is null and hence the return value is the result of invoking the whenNull delegate. Hence, the result of the whole expression person.Attribute("gender").NotNull(x => x.Value, () => "male") is the string "male"

Going back to the contrived example of the classes A, B and C discussed at the beginning of this article, let me introduce an 'artificial' requirement. If the value of the c member of an object of class B is null, we would like to use the following instance of C:

C#
readonly C defC = new C { name = "Krishna" };

This means given the following C# statement,

C#
var a = new A { b = new B() };

the expression a.b.c.name must return the string "Krishna".

Obviously, as seen earlier, the above expression will fail at runtime with a NullReferenceException. We can use our NotNull methods to address the problem in an elegant way:

C#
a.NotNull(x => x.b).NotNull(x => x.c).NotNull(x => x, () => defC).name

In the above expression, the third call to NotNull uses the second overload, while the first two calls use the first overload. In this specific case, the return value from the second call to NotNull is null which is passed to the third call to NotNull. Since the a parameter of the NotNull method is null, the delegate reference by the whenNull parameter is invoked. In the above expression, we pass the lambda expression () => defC to this delegate which simply returns the object referenced by the defC variable. Finally, the name member of this object is referenced. Thus the string "Krishna" is the result of this expression. What if the c member was not null? In that case, the third call to NotNull uses the first lamda expression: x => x, which simply returns the object referenced by c. The result of the whole expression would then be whatever value the name member of the object referenced by c had at that time.

Incidentally, the expression accessing the name member as shown above would return "Krishna" even in cases where any of the objects in the method chain were null! For example, if a were defined like this:

C#
A a = null;

Then the expression:

C#
a.NotNull(x => x.b).NotNull(x => x.c).NotNull(x => x, () => defC).name

would still return "Krishna"!. Why? The first call to NotNull would return null as that's the default value for objects of type A. Due to this, the second call to NotNull would also return null. The third call would therefore invoke its second delegate parameter, which would return "Krishna". Thus, a null somewhere down the chain has a propagation effect. This may be the reason why some refer to the safe navigation operator as Null Propagation Operator.

Conclusion

In this article, we saw the problem of using the '.' operator in a chained fashion could lead to the dreaded NullReferenceException. I presented the safe navigation operator. There's no such operator in C#. But, there's one planned in the upcoming release. Are we condemned to writing 'ugly' code using the ternary operator in a conditional expression or using some similar construct if we need to ensure exception safety? This article presented an elegant way of using generic extension methods that provided an elegant solution to this problem. We also saw how these methods can even surpass the power of the safe navigation operator when it does make its way into C#.

Enjoy programming!

Using the Code

The accompanying source code is a Visual Studio 2010 project. The project contains a single C# file, which you could compile and run from the command line too.

Points of Interest

The power of generics and lambda expressions in bestowing us, the programmers, in expressing our intent is noteworthy.

History

This is the first version of this article. If some of you, my readers, do not understand the examples using XElement or XAttribute the .NET XML API, I can give helpful pointers. This article is dedicated to my dear spiritual master His Divine Grace A. C. Bhaktivedanta Swami Prabhupada.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
India India
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionGreat article! One question though... Pin
MegaJar6-Feb-15 5:57
MegaJar6-Feb-15 5:57 
AnswerRe: Great article! One question though... Pin
Ganesh A Hegde8-Feb-15 5:33
professionalGanesh A Hegde8-Feb-15 5:33 
GeneralRe: Great article! One question though... Pin
MegaJar9-Feb-15 2:17
MegaJar9-Feb-15 2:17 
GeneralRe: Great article! One question though... Pin
Ganesh A Hegde9-Feb-15 17:57
professionalGanesh A Hegde9-Feb-15 17:57 
QuestionInsufficient Implementation Pin
Youzelin25-Nov-14 20:07
Youzelin25-Nov-14 20:07 
AnswerRe: Insufficient Implementation Pin
Ganesh A Hegde26-Nov-14 6:45
professionalGanesh A Hegde26-Nov-14 6:45 
GeneralRe: Insufficient Implementation Pin
Youzelin29-Nov-14 0:24
Youzelin29-Nov-14 0:24 
Mmm......, yeah, you are right! I forgot this is an extension method! cool! So, thank you for your sharing. Big Grin | :-D
GeneralMy vote of 4 Pin
Klaus Luedenscheidt20-Nov-14 17:04
Klaus Luedenscheidt20-Nov-14 17:04 
GeneralRe: My vote of 4 Pin
Ganesh A Hegde20-Nov-14 20:39
professionalGanesh A Hegde20-Nov-14 20:39 
GeneralRe: My vote of 4 Pin
crash-droid21-Nov-14 16:48
crash-droid21-Nov-14 16:48 
GeneralRe: My vote of 4 Pin
Ganesh A Hegde22-Nov-14 20:51
professionalGanesh A Hegde22-Nov-14 20:51 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.