Safe navigation operator in C #?

Possible duplicate:
Label for "null if the object is null, or object.member if the object is not null

Some languages ​​have a safe navigation operator that lets you not worry about null link exceptions.

Groovy language example:

String lname = person.Name.ToLowerCase(); //throws exception if Name is null String lname = person.Name?.ToLowerCase();//lname will be null if Name was null 

How can I do something like this in C #? My solution so far is an extension method as follows:

 public static T o<T>(this T obj) where T : new() { return obj != null ? obj : new T(); } //used like: String lname = person.o().Name; //returns null if person was null 

However, this only works in some cases.

+6
c #
source share
4 answers

In such cases, I use an extension method called IfNotNull :

 public static OUT IfNotNull<IN, OUT>(this IN v, Func<IN, OUT> f) where IN : class where OUT : class { return v == null ? null : f(v); } 

More complex is the introduction of the concept of "Possible." An example was given by derick bailey here .

Update:

In C # 6, there is now a zero-spread operator that syntactically looks exactly like Groovy.

+9
source share

Are you looking for a short-circuited undefined member access operator ?. which was introduced in C # language version 6 (released in Visual Studio 2015).

The rest of my answer was written for earlier versions of C # that didn't have a statement ?. .


Generally speaking, if you are in a situation where you are accessing a deeply "nested" property, such as outermostObject.abcX , you should probably consider redesigning your code, since such access may indicate that you are violating the established principles of the TOE ( such as the principle of least knowledge, as well as the Law of Demeter).

Some other options:

First , anti-offer; do not do this:

 string lname = null; try { lname = Person.Name.ToLower(); } catch (NullReferenceException ex) { } // inefficient and ugly 

Second , using something like Maybe monad - you can define this type yourself. This is basically a Nullable<T> that implements IEnumerable<T> so that it returns an empty sequence when no value is given, or a sequence of exactly one element if the value is set. Then you will use it as follows:

 Maybe<string> personName = person.Name; var lname = (from name in personName select name.ToLower()).FirstOrDefault(); 

The third and perhaps the simplest and most practical solution suggested by ulrichb:

 var lname = person.Name != null ? person.Name.ToLower() : null; 

PS , since we are already talking about checking for null , do not forget to check if there is a person null before accessing the Name property ..; -)

+4
source share

I don't know about returning null from something that is guaranteed not to be null, but you can use the Null Coalescing Operator ?? to guarantee an object reference ??

Something like:

 string lname = (person.Name??String.Empty).ToLower(); 

It will return an empty string instead of zero for the null case, but it will work.

Returning an empty string makes more sense than returning null; if you return zero, it will throw again if you attach another operator to it.

+3
source share

Doesn't exist in C # today, but you can write it using SelectMany .

 String lname = from _ in person.Name from s in _.ToUpper() select s; 

or

 String lname = person.Name.SelectMany(_ => _.ToUpper(), s => s); 

(This is a proposal by Bart De Smet in his discussion of PDC 2010 about the future of LINQ . See slide # 6.)

+2
source share

All Articles