7

Possible Duplicate:
Shortcut for “null if object is null, or object.member if object is not null”

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

Example of the language Groovy:

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 accomplish something similar to this in C#? My solution so far is an extension method like this:

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.

Community
  • 1
  • 1
Kyle
  • 21,377
  • 37
  • 113
  • 200
  • http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/3990187-add-operator-to-c-?tracking_code=594c10a522f8e9bc987ee4a5e2c0b38d – Hawxby Mar 05 '14 at 13:40
  • At this time of writing, such a feature is actually planned for C# 6: see [.NET Compiler Platform ("Roslyn"): Language feature status: Null propagating operator `?.`](http://roslyn.codeplex.com/discussions/540883) – stakx - no longer contributing Jul 30 '14 at 13:40

4 Answers4

10

For such cases I tend to 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 sophisticated is to introduce the notion of a Maybe . An example was brought by derick bailey here.

Update:

As of C# 6 there is now a null-propagating operator which syntax-wise looks exactly like the Groovy one.

flq
  • 22,247
  • 8
  • 55
  • 77
  • 1
    This seems like a pretty good solution. Allows you to not break method chaining and not have to introduce a temporary variable, which are the main reasons I want to use a safe navigation operator. – Kyle Nov 05 '10 at 22:52
  • 1
    This is dependent on `OUT` being a nullable type. You can extend this to all types by: 1. remove `where OUT : class`, 2. alter the body to `return v == null ? default(OUT) : f(v);`. – Paul Fleming Jul 26 '13 at 09:42
  • How does v derive from o? That's the whole point, to be able to do sth with o if it is not null. – flq Dec 03 '14 at 22:08
5

You are looking for the short-circuiting null-conditional member access operator ?. that was introduced in C# language version 6 (rolled out in Visual Studio 2015).

The remainder of my answer was written for earlier versions of the C# language which did not have the ?. operator.


Generally speaking, if you're in a situation where you are accessing a deeply "nested" property, such as outermostObject.a.b.c.X, you should probably consider re-designing your code, as such an access could indicate that you're violating established OO principles (such as the principle of least knowledge, a.k.a. Law of Demeter).

Some other options:

First, an anti-suggestion — don't do this:

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

Second, using something like a Maybe monad — you can define such a type yourself. It's basically a Nullable<T> that implements IEnumerable<T> such that it returns an empty sequence when no value is set, or a sequence of exactly one element if a value is set. You'd then use it as follows:

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

Third, and probably the easiest and most practical solution, as suggested by ulrichb:

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

P.S., since we're already on the topic of checking for null, don't forget to check whether person is null before accessing its Name property... ;-)

stakx - no longer contributing
  • 83,039
  • 20
  • 168
  • 268
3

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

Something like:

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

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

Returning an empty string makes more sense than returning a null; if you return a null, it will throw again if you chain another operator onto it.

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
2

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

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

or

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

(That was Bart De Smet's proposal in his PDC 2010 talk on the future of LINQ. See slide #6.)

sblom
  • 26,911
  • 4
  • 71
  • 95
  • 1
    Note that `SelectMany` in this case isn't the usual LINQ `SelectMany` but a custom `SelectMany` created to implement the `Maybe` monad. – Martin Liversage May 24 '11 at 07:54