6

So there is the coalescing operator ?? that allows handy handling of null objects (IE. MyDisplayString = MyString ?? "n/a";)

but is there a nice fancy operator for handling a similar situation on properties of objects? For instance lets say that the property you are interested in is a property of a property like: MyDataObject.MySubModel.MyProperty

If MyProperty is null you want coalesce to "n/a". You can use ?? here, but what if MyDataObject is null or MyDataObject.MySubModel?

This also comes up with XML when trying to get optional attributes and elements of an element. IE: MyString = MyElement.Attribute("MyOptionalAttribute").Value ?? "n/a"; fails if the attribute isn't there.

Is there a nice fancy way of handling this scenario?

user229044
  • 232,980
  • 40
  • 330
  • 338
Mr Bell
  • 9,228
  • 18
  • 84
  • 134
  • 1
    I would think you would want to impliment that in the getter of the class property... – Ryan Bennett Oct 05 '10 at 16:57
  • 2
    possible duplicate of [Shortcut for "null if object is null, or object.member if object is not null"](http://stackoverflow.com/questions/3817930/shortcut-for-null-if-object-is-null-or-object-member-if-object-is-not-null) – dtb Oct 05 '10 at 17:07
  • 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:07
  • possible duplicate of [Deep Null checking, is there a better way?](http://stackoverflow.com/questions/2080647/deep-null-checking-is-there-a-better-way) – Liam Oct 16 '13 at 10:06

6 Answers6

6

Is there a nice fancy way of handling this scenario?

You are not the first one asking for this feature. One way is to write a "With" extension method to fetch property values, since extension methods can handle being called on a null reference. Instead of

thing.Foo.Bar

you would write

thing.With(x => x.Foo).With(x => x.Bar)
Community
  • 1
  • 1
Wim Coenen
  • 66,094
  • 13
  • 157
  • 251
  • Is there any performance penalty for using `with`? (probably a micro-optimization question but I'd still like to know) – ahsteele Oct 05 '10 at 17:09
  • @ahsteele: assuming you need to do the if-check anyway, the performance impact is that of two extra method calls (the extension method and the delegate invocation). I have written this to test it: http://dl.dropbox.com/u/119154/permalink/ifvswith.txt – Wim Coenen Oct 05 '10 at 17:37
  • Your timing test is misleading. You are allocating two delegate instances which (under x64) need 2*64 bytes = 128bytes per call. If you call this millions of times you are allocating gigabytes of temp data which will cost much GC time. – Alois Kraus May 27 '15 at 20:57
  • @AloisKraus: I guess it doesn't matter anymore now that the C# 6.0 null-conditional operator is just around the corner. – Wim Coenen May 28 '15 at 00:04
  • @Wim Coenen: Not everyone will use C# 6.0 right away. These people will stick to the next "best" solution which is in reality a poorly performing "solution". But now they are warned and understand perhaps better why their LINQ queries in very often called functions make things significantly slower. It is no accident that the inventors of LINQ have banned LINQ from the Roslyn codebase due to hard to spot perf issues (see https://github.com/dotnet/roslyn/wiki/Contributing-Code). – Alois Kraus May 28 '15 at 17:28
4

In C# 5 and below as stated in other answers you need to build something yourself. Instead of using an Extension method as others have here we use a Helper, that we call NN since we use it a LOT, especially in Razor.

public static TValue N<TParent, TValue>(TParent o, Func<TParent, TValue> accessor, TValue defaultValue)
{
    if (o == null)
        return defaultValue;

    return accessor(o);
}

/// <summary>
/// Guarantees return of null or value, given a prop you want to access, even if the parent in the first argument
/// is null (instead of throwing).
/// 
/// Usage:
/// 
/// NN.N(myObjThatCouldBeNull, o => o.ChildPropIWant)
/// </summary>
/// <returns>The value of the prop. Null if the object is null, or if the child prop is null.</returns>
public static TValue N<TParent, TValue>(TParent o, Func<TParent, TValue> accessor)
    where TValue : class
{
    return NN.N(o, accessor, null);
}

We actually use a few helpers depending on the desired behavior when null is encountered; for example you might be accessing an int property and want 0. Full code in the linked Gist.

In C# 6, you can use the null property coalescence operator:

myObjThatCouldBeNull?.ChildPropIWant

More about it:

https://roslyn.codeplex.com/discussions/540883

Chris Moschini
  • 36,764
  • 19
  • 160
  • 190
2

The Null Object Pattern

a Null Object is an object with defined neutral ("null") behavior

may help you avoid this problem.

Another option is to use extension methods, then you can say:

if (Contract
    .NullSafe(c => c.Parties)
    .NullSafe(p => p.Client)
    .NullSafe(c => c.Address) != null)
{
    // do something with the adress
    Console.Writeline(Contract.Parties.Client.Adress.Street);
}
Ian Ringrose
  • 51,220
  • 55
  • 213
  • 317
2

As I noted here:

Shortcut for "null if object is null, or object.member if object is not null"

this is a fairly frequently requested feature that did not make the bar for C# 4. We'll consider it for hypothetical future versions of the language, but it is not high on the priority list so I would not hold out much hope if I were you.

Community
  • 1
  • 1
Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
0

There might be a better or more elegant way of handling the issue you're describing, but I've found that typically I have to check for nulls along the way, i.e.:

MyString = MyElement.Attribute("MyOptionalAttribute") != null ? MyElement.Attribute("MyOptionalAttribute").Value : "n/a";
Brian Driscoll
  • 19,373
  • 3
  • 46
  • 65
0

In the case of XElement/XAttribute, you can use the explicit conversion operators:

string myString = (string)myElement.Attribute("MyOptionalAttribute") ?? "n/a";

For the general case, a 'safe dereferencing operator' is a fairly frequently requested feature.

Community
  • 1
  • 1
dtb
  • 213,145
  • 36
  • 401
  • 431