Is there such a thing as a chained NULL check?

I have the following ugly code:

if (msg == null || msg.Content == null || msg.Content.AccountMarketMessage == null || msg.Content.AccountMarketMessage.Account == null || msg.Content.AccountMarketMessage.Account.sObject == null) return; 

Is there a way to check the chain for null values โ€‹โ€‹in C #, so that I don't need to check every single level?

+7
c #
source share
7 answers

One suggestion in C # 6 will be the addition of a new Null Propogation statement .

This (hopefully) allows you to write:

 var obj = msg?.Content?.AccountMarketMessage?.Account?.sObject; if (obj == null) return; 

Unfortunately, there is nothing in this language that would handle this.

+9
source share

This is currently not happening, but it may soon appear in .NET. There is a well-known stream of User Voice on this subject . And, as noted in this article , the Visual Studio team recently announced that:

We are seriously considering this feature for C # and VB, and will be prototyping it in the coming months.

Edit: and as stated in Reed Copsey's answer above , this is now a planned addition to C # 6. The Codeplex pages he linked have more details.

+4
source share

There is no built-in support for this, but for this you can use the extension method:

 public static bool IsNull<T>(this T source, string path) { var props = path.Split('.'); var type = source.GetType(); var currentObject = type.GetProperty(props[0]).GetValue(source); if (currentObject == null) return true; foreach (var prop in props.Skip(1)) { currentObject = currentObject.GetType() .GetProperty(prop) .GetValue(currentObject); if (currentObject == null) return true; } return false; } 

Then call it:

 if ( !msg.IsNull("Content.AccountMarketMessage.Account.sObject") ) return; 
+2
source share

You need monads and a monadic null check. You can see the package Monads.Net . This can help simplify null tests and get values โ€‹โ€‹from deep navigational properties.

Something like

 var sObject = person.With(p=>p.Content).With(w=>w.AccountMarketMessage ).With(p=>p.Account).With(p=>p.Object); 

If you need a default value then

 var sObject = person.With(p=>p.Content).With(w=>w.AccountMarketMessage).With(p=>p.Account).Return(p=>p.Object, "default value"); 
+2
source share

You can lazily evaluate values โ€‹โ€‹using lambda expressions. This is an excess for a simple zero check, but it can be useful for more complex expressions of more complex expressions.

Example

 // a type that has many descendents var nested = new Nested(); // setup an evaluation chain var isNull = NullCheck.Check( () => nested ) .ThenCheck( () => nested.Child ) .ThenCheck( () => nested.Child.Child ) .ThenCheck( () => nested.Child.Child.Child ) .ThenCheck( () => nested.Child.Child.Child.Child ); // handle the results Console.WriteLine( isNull.IsNull ? "null" : "not null" ); 

The code

This is a complete example (albeit a draft code) that can be inserted into a console application or LINQPad.

 public class Nested { public Nested Child { get; set; } } public class NullCheck { public bool IsNull { get; private set; } // continues the chain public NullCheck ThenCheck( Func<object> test ) { if( !IsNull ) { // only evaluate if the last state was "not null" this.IsNull = test() == null; } return this; } // starts the chain (convenience method to avoid explicit instantiation) public static NullCheck Check( Func<object> test ) { return new NullCheck { IsNull = test() == null }; } } private void Main() { // test 1 var nested = new Nested(); var isNull = NullCheck.Check( () => nested ) .ThenCheck( () => nested.Child ) .ThenCheck( () => nested.Child.Child ) .ThenCheck( () => nested.Child.Child.Child ) .ThenCheck( () => nested.Child.Child.Child.Child ); Console.WriteLine( isNull.IsNull ? "null" : "not null" ); // test 2 nested = new Nested { Child = new Nested() }; isNull = NullCheck.Check( () => nested ).ThenCheck( () => nested.Child ); Console.WriteLine( isNull.IsNull ? "null" : "not null" ); // test 3 nested = new Nested { Child = new Nested() }; isNull = NullCheck.Check( () => nested ).ThenCheck( () => nested.Child ).ThenCheck( () => nested.Child.Child ); Console.WriteLine( isNull.IsNull ? "null" : "not null" ); } 

Again: you probably shouldn't use this instead of simple null checks due to the complexity it introduces , but this is an interesting pattern.

+2
source share

.NET Fiddle

As indicated, is there a plan for C # 6.0 to implement the operator ? to facilitate this process. If you cannot wait, I would suggest using a lambda expression and a simple helper function to solve this problem.

 public E NestedProperty<T,E>(T Parent, Func<T,E> Path, E IfNullOrEmpty = default(E)) { try { return Path(Parent); } catch { return IfNullOrEmpty; } } 

This can be used int value = NestedProperty<First,int>(blank,f => f.Second.Third.id); as shown in the demo below

program

 public class Program { public void Main() { First blank = new First(); First populated = new First(true); //where a value exists int value = NestedProperty<First,int>(blank,f => f.Second.Third.id); Console.WriteLine(value);//0 //where no value exists value = NestedProperty<First,int>(populated,f => f.Second.Third.id); Console.WriteLine(value);//1 //where no value exists and a default was used value = NestedProperty<First,int>(blank,f => f.Second.Third.id,-1); Console.WriteLine(value);//-1 } public E NestedProperty<T,E>(T Parent, Func<T,E> Path, E IfNullOrEmpty = default(E)) { try { return Path(Parent); } catch { return IfNullOrEmpty; } } } 

simple demo structure

 public class First { public Second Second { get; set; } public int id { get; set; } public First(){} public First(bool init) { this.id = 1; this.Second = new Second(); } } public class Second { public Third Third { get; set; } public int id { get; set; } public Second() { this.id = 1; this.Third = new Third(); } } public class Third { public int id { get; set; } public Third() { this.id = 1; } } 
0
source share

Starting with version 3.5 (possibly earlier), you can write a very simple extension method

  public static TResult DefaultOrValue<T, TResult> (this T source, Func<T, TResult> property) where T : class { return source == null ? default(TResult) : property(source); } 

You can call this method even shorter and then use like this

  var instance = new First {SecondInstance = new Second {ThirdInstance = new Third {Value = 5}}}; var val = instance .DefaultOrValue(x => x.SecondInstance) .DefaultOrValue(x => x.ThirdInstance) .DefaultOrValue(x => x.Value); Console.WriteLine(val); Console.ReadLine(); 

therefore source classes:

 public class Third { public int Value; } public class First { public Second SecondInstance; } public class Second { public Third ThirdInstance; } 
0
source share

All Articles