58

Basic question here - I have many lines of code that look something like:

var a = (long_expression == null) ? null : long_expression.Method();

Similar lines repeat a lot in this function. long_expression is different every time. I am trying to find a way to avoid repeating long_expression, but keeping this compact. Something like the opposite of operator ??. For the moment I'm considering just giving in and putting it on multiple lines like:

var temp = long_expression;
var a = (temp == null) ? null : temp.Method();

But I was curious if there is some clever syntax I don't know about that would make this more concise.

tenfour
  • 36,141
  • 15
  • 83
  • 142
  • 3
    `var a = temp ? null : temp.Method();` I think you meant to have `var a = temp == null ? null : temp.method();` Small detail though – Sephallia Jun 29 '12 at 19:08
  • I think your current method is the way to go. – Jonathon Reinhart Jun 29 '12 at 19:08
  • 3
    "Best syntax" under the constraint "language == C#", or for stuff like that in general? Obviously something like this can be written rather better in a functional language, using (applicative) functors / monads and suchlike. – leftaroundabout Jun 29 '12 at 22:03
  • 2
    @leftaroundabout: Yeah, this operation is precisely `>>=` for the `Maybe` monad. – Jon Purdy Jun 30 '12 at 00:01
  • 1
    Although it's minor, I really think reversing the logic to: "long_expression != null ? long_expression.Method() : null" is more clear - with the important logic coming first. It's also consistent with logic such as "if (long_expression != null) do_something", which is how this would be written if it wasn't a variable initialization. – Ken Beckett Jul 03 '12 at 18:57
  • possible duplicate of [How to check for nulls in a deep lambda expression?](http://stackoverflow.com/questions/854591/how-to-check-for-nulls-in-a-deep-lambda-expression) – nawfal Oct 10 '13 at 06:08

7 Answers7

77

Well, you could use an extension method like this:

public static TResult NullOr<TSource, TResult>(this TSource source,
    Func<TSource, TResult> func) where TSource : class where TResult : class
{
    return source == null ? null : func(source);
}

Then:

var a = some_long_expression.NullOr(x => x.Method());

Or (depending on your version of C#)

var a = some_long_expression.NullOr(Foo.Method);

where Foo is the type of some_long_expression.

I don't think I would do this though. I'd just use the two line version. It's simpler and less clever - and while "clever" is fun for Stack Overflow, it's not usually a good idea for real code.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    Beat me to it! I was about to post something like this. – Mike Bailey Jun 29 '12 at 19:09
  • 4
    I've always disliked extension-methods that runs on null-references. Calling methods on null should IMO always throw a Null Reference Exception. I know extension-methods are in fact static helper methods, but that's not always clear to the reader of the code. – Pauli Østerø Jul 02 '12 at 23:50
  • 1
    It may be inconsistent, but it's also incredibly useful. There are methods which previously, had to be static class methods, that are much more discoverable as extension methods that operate on null values. Adding an extension method of IsNullOrWhiteSpace on String is a great example. – MgSam Jul 15 '12 at 16:35
  • 1
    @JonSkeet: You said you wouldn't use this method; is that personal preference, or is there some risk / impact to using it? I ask as this looks like an ideal workaround to me (until we get a `?.` operator (https://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/3990187-add-operator-to-c) or a `!??` operator which acts as a reverse `??`) – JohnLBevan Jul 14 '14 at 11:23
  • 1
    @JohnLBevan: Personal preference - I generally favour simple code over "clever" code. I don't know of any *risk* in using it. – Jon Skeet Jul 14 '14 at 11:30
  • NB: found a side effect of trying to be clever: `LINQ to Entities does not recognize the method 'System.String NullSafe` (using slightly different version of the method which catered for both reference and value types: http://blogs.infosupport.com/blogs/frankb/archive/2008/02/02/Using-C_2300_-3.0-Extension-methods-and-Lambda-expressions-to-avoid-nasty-Null-Checks.aspx) – JohnLBevan Jul 14 '14 at 16:37
  • I can't get the code to compile. it complains about not finding TResult... googled for a bit but didn't figure it out – wintersylf May 15 '15 at 05:00
  • @wintersylf: `TResult` is a type parameter in the generic method. Without seeing what you're trying, I can't see where your mistake is - but this code *does* compile. – Jon Skeet May 15 '15 at 05:44
  • are there any includes I need to have, and/or can I drop this into any namespace/class/file? – wintersylf Jun 02 '15 at 16:54
  • 1
    @wintersylf: Well you'll need a `using` directive for the `System` namespace in the place where you're declaring the `NullOr` method, and you'll need a `using` directive for whichever namespace contains the class that declares the extension method, wherever you want to *use* the extension method, but that's all. – Jon Skeet Jun 02 '15 at 16:59
49

I found this answer insightful.

By doing this assignment, you are propagating the null deeper into the system. You'll have to write your null handling condition again (and again and again) to handle these propagations.

Instead of allowing execution to continue with nulls, replace the null with a better representation (quoted from link)

  1. If the null represents an empty collection, use an empty collection.
  2. If the null represents an exceptional case, throw an Exception.
  3. If the null represents an accidentally uninitialized value, explicitly initialize it.
  4. If the null represents a legitimate value, test for it - or even better use a NullObject that performs a null op.

In particular, replacing a null collection reference with an empty collection has saved me many null tests.

Community
  • 1
  • 1
Amy B
  • 108,202
  • 21
  • 135
  • 185
  • I very much agree; but unfortunately, in many situations you find yourself working with an API or legacy code that uses null a lot. – Nate C-K Jul 04 '12 at 14:55
5
var x = "";

/* try null instead */
string long_expression = "foo";

var a = ((x = long_expression) == null) ? null : x.ToUpper();

/* writes "FOO" (or nothing) followed by newline */
Console.WriteLine(a);

The type of the initialization value of x must be compatible to the type of long_expression (here: string). Works with the Mono C# compiler, version 2.10.8.1 (from Debian package mono-gmcs=2.10.8.1-4).

PointedEars
  • 14,752
  • 4
  • 34
  • 33
  • @MirceaChirea OK, then. Does it *work* in C#? I cannot test here. – PointedEars Jun 30 '12 at 07:08
  • yes it does. var just tells the compiler to infer the type from the expression; particularly useful with long types like IEnumerable. – CMircea Jun 30 '12 at 08:17
  • @MirceaChirea Thanks, I looked it up in the [Specification](http://msdn.microsoft.com/en-us/library/ms228593.aspx) already :) Testing with [Mono](http://www.mono-project.com/Main_Page) now. – PointedEars Jun 30 '12 at 08:19
5

I think the C# language could really use a new operator for this sort of logic - it's quite common, and an operator would simplify countless lines of code out there.

We need something along the lines of the "??" or "if null then" operator, but that works as special '.' dot operator with a "if not null" condition. For "??", the first '?' is like the 'if' part of the "?:" if-then, and the second '?' represents 'null' like for nullable types. I think we need a ".?" operator which works just like '.', except it simply evaluates to null if the left expression is null instead of throwing an exception. I guess it would be a "dot not null" operator (OK, so maybe ".!?" would be more logical, but let's not go there).

So, your oh-so-common example could lose the redundant symbol name like this:

var a = long_expression.?Method();

There is a ton of C# code out there with nested null checks that would benefit greatly. Just think how nice it would if this:

if (localObject != null)
{
    if (localObject.ChildObject != null)
    {
        if (localObject.ChildObject.ChildObject != null)
            localObject.ChildObject.ChildObject.DoSomething();
    }
}

could become just:

localObject.?ChildObject.?ChildObject.?DoSomething();

There is also a ton of code where null checks that should be there are missing, resulting in occasional runtime errors. So, actually using the new '.?' operator by default would eliminate such problems... It's perhaps unfortunate that we couldn't reverse the behavior of '.' and '.?' at this point, so only the new '.?' throws an exception if the left side is null - it would be the cleaner and more logical way to go, but breaking changes are very bad. Although, one could argue that this particular change would be likely to fix a lot of hidden problems, and unlikely to break anything (only code that expects a null ref exception to be thrown). Oh, well... one can always dream...

The only downside to checking for the null is really the slight performance hit, which is most assuredly why '.' doesn't check for null. But, I really think the ability to just use '.?' when you care about performance (and know the left side will never be null) would have been the better way to go.

On a similar note, having 'foreach' check for and ignore a null collection would have also been so much nicer. No more need to wrap most 'foreach' statements with "if (collection != null)", or worse, develop the common habit of always using empty collections instead of null ... which is fine in some cases, but an even worse performance issue than the null check when this is done in complex object trees where the majority of the collections are empty (which I've seen a lot). I think the good intention of not having 'foreach' check for null to provide better performance has backfired in the majority of cases.

Anders, it's never too late to make such changes, and add a compiler switch to enable them!

Ken Beckett
  • 1,273
  • 11
  • 13
  • 1
    that's called the null safe navigator. See here for a response by a member of the C# language team: http://stackoverflow.com/a/3818256/45583 – Fowl Jul 06 '12 at 05:06
  • 1
    The opposite of ?? is obviously !?? which is what the operator should be. – Amy B Jul 13 '12 at 19:24
  • @DavidB - we're not talking about an opposite of '??', but a null safe version of '.', which is a completely different operator. My reference to '??' was only background as to why '.?' might make sense, but others have apparently already come to the same conclusion. – Ken Beckett Jul 14 '12 at 00:00
1

You can write an extension method for whatever type long_expression evaluates to:

public static object DoMethod(this MyType pLongExpression)
{
   return pLongExpression == null ? null : pLongExpression.Method();
}

This will be callable on any MyType reference, even if that reference is null.

Dave Cousineau
  • 12,154
  • 8
  • 64
  • 80
  • 1
    I've always disliked extension-methods that runs on null-references. Calling methods on null should IMO always throw a Null Reference Exception. I know extension-methods are in fact static helper methods, but that's not always clear to the reader of the code. – Pauli Østerø Jul 04 '12 at 08:44
  • From OP - the long expression is different every time (can also mean the return type). – nawfal Oct 10 '13 at 05:38
0

You could put long_expression == null into a function with a short name and just call that function each time.

Daniel
  • 6,595
  • 9
  • 38
  • 70
0

if (!String.IsNullOrEmpty(x)) x.func()

Hamit YILDIRIM
  • 4,224
  • 1
  • 32
  • 35