135

Note: This question was asked before the introduction of the .? operator in C# 6 / Visual Studio 2015.

We've all been there, we have some deep property like cake.frosting.berries.loader that we need to check if it's null so there's no exception. The way to do is is to use a short-circuiting if statement

if (cake != null && cake.frosting != null && cake.frosting.berries != null) ...

This is not exactly elegant, and there should perhaps be an easier way to check the entire chain and see if it comes up against a null variable/property.

Is it possible using some extension method or would it be a language feature, or is it just a bad idea?

Homde
  • 4,246
  • 4
  • 34
  • 50
  • 3
    I've wished for that often enough - but all ideas I've came up were worse than the actual problem. – peterchen Jan 17 '10 at 11:35
  • Thanks for all the answers and interesting to see that other people have had the same thoughts. I got to thinking on how I'd like to see this solved myself and although Eric's solutions is nice i think i'd simply to write something like this if (IsNull(a.b.c)) , or if (IsNotNull(a.b.c)) but maybe that's just to my taste :) – Homde Jan 17 '10 at 19:54
  • When you instantiate frosting, it has a property of berries, so at that point in your constructor, can you just tell frosting that whenever it is instatiated to create an empty (not-null) berries? and whenever berries is modified frosting does the check of the value???? – Doug Chamberlain Feb 14 '11 at 21:13
  • Somewhat loosely related, some of the techniques here I found preferable for the "deep nulls" problem I was trying to get around. http://stackoverflow.com/questions/818642/singleordefault-how-to-change-the-default-values – AaronLS Jul 06 '12 at 19:32
  • 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:21
  • The **Safe Navigation Operator** coming in the next version of C#: [*MSDN Blogs*] [**At last, C# is getting “?.”, sometimes called the Safe Navigation Operator**](http://blogs.msdn.com/b/jerrynixon/archive/2014/02/26/at-last-c-is-getting-sometimes-called-the-safe-navigation-operator.aspx) – KMoraz Mar 05 '14 at 15:24

16 Answers16

227

We have considered adding a new operation "?." to the language that has the semantics you want. (And it has been added now; see below.) That is, you'd say

cake?.frosting?.berries?.loader

and the compiler would generate all the short-circuiting checks for you.

It didn't make the bar for C# 4. Perhaps for a hypothetical future version of the language.

Update (2014): The ?. operator is now planned for the next Roslyn compiler release. Note that there is still some debate over the exact syntactic and semantic analysis of the operator.

Update (July 2015): Visual Studio 2015 has been released and ships with a C# compiler that supports the null-conditional operators ?. and ?[].

stakx - no longer contributing
  • 83,039
  • 20
  • 168
  • 268
Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • 1
    Love it but without the ., i.e. cake?frosting?berries?loader. I also want similar functionality for the null coalescing operator: return cake.frosting ?? new ButterCream(); – Jamie Ide Jan 17 '10 at 18:20
  • 10
    Without the dot it becomes syntactically ambiguous with the conditional (A?B:C) operator. We try to avoid lexical constructs that require us to "look ahead" arbitrarily far in the token stream. (Though, unfortunately, there already are such constructs in C#; we'd rather not add any more.) – Eric Lippert Jan 17 '10 at 18:44
  • 5
    While I would welcome a null-safe dereference operator, the `.?` is a bit hard on the eyes. I would propose something like `..` instead. On a separate note, out of curiosity, what are some examples of lexical constructs in C# that require arbitrarily long look ahead? – LBushkin Jan 18 '10 at 05:20
  • @LBushkin - There's plenty of things which are not used for operators, today, that are as of C# 4.0, and to my knowledge illegal. i.e. # and $, so you could write cake#frosting#berries that are not ambiguous. @Eric - I think adding a .? operator will be unnecessary, if you think about another promise, which is to open up the compiler as a service. I'm not really sure what Anders means about that, but I have an idea myself. And that's to be able to manipulate expression trees at compile time. It would allow for a lot more language flexibility and it won't require new operators. – John Leidegren Jan 18 '10 at 15:59
  • 3
    @LBushkin: We also do deep lookahead when attempting to figure out is "(something)anotherthing" a cast and its operand, or a parenthesized expression followed by anotherthing. For example, "(Foo.Bar)/Blah" vs "(Foo.Bar)Blah". The rules here are quite complicated, see section 7.6.6 for details. Or section 7.5.4.2 also has some interesting situations where parsing requires considerable lookahead and heuristics. – Eric Lippert Jan 19 '10 at 16:56
  • please don't add it, this is problem that is not very common – Ian Ringrose Feb 07 '10 at 21:22
  • 34
    @Ian: this problem is *extremely* common. This is one of the most frequent requests that we get. – Eric Lippert Feb 08 '10 at 03:29
  • 1
    There's a .Net language, called Oxygene, which has this feature a while now. ( http://prismwiki.codegear.com/en/Colon_Operator ) I used to write some parts of my software in it, and I really, really miss this operator. It would turn value type-results into nullables. And you could call the methods of the value type that is nullable directly, w/o going through GetValueOrDefault. Nullable x; x:SomeMethod(); – Robert Giesecke Feb 08 '10 at 05:29
  • 1
    @Eric, maybe because I know the Null Object Pattern and tend to avoid code the reach deep into other objects I don't hit this. – Ian Ringrose Feb 08 '10 at 08:01
  • 7
    @Ian: I also prefer to use the null object pattern when feasible to do so, but most people do not have the luxury of working with object models that they themselves designed. Lots of existing object models use nulls and so that's the world we have to live with. – Eric Lippert Feb 08 '10 at 09:13
  • 2
    @Eric - If you give a man a fish, he will be fed for the day, if you teach the man to fish, he'll never go hungry again, or so I've heard. If you you give inexperienced programmers a short-hand notation to avoid thinking about the problems, I reckon I'll be having an even more difficult time trying to convince our development team to think about the architectural implications of they way they write code. You should promote more good language practices than giving people cheap tricks of getting out of a bad situation. – John Leidegren Feb 20 '10 at 09:24
  • 12
    @John: We get this feature request almost entirely *from* our most experienced programmers. The MVPs ask for this *all the time*. But I understand that opinions vary; if you'd like to give a constructive language design suggestion in addition to your criticism, I'm happy to consider it. – Eric Lippert Feb 20 '10 at 15:38
  • 5
    @Eric - My original proposition was to expose expression trees at compile time. I strongly believe in turning the compiler in to a service I can control and it won't really require any syntactic sugar. e.g. Coal(x => x.cake.frosting.color) is transformed at compile time into appropriate short circuiting code by the compile time transform Coal. Coal looks something like this, const Expression> Coal(this T obj, Expression> expr). I've re-purposed the const keyword to act as both a static modifier and compile time flag. The returned expression tree is emitted as IL. – John Leidegren Feb 20 '10 at 17:26
  • Eric, My vote is with @John DONT add this. I have never found a single use-case for this kind of multiple if nulls check that does not lead to a bad bad code behind. – chakrit Feb 06 '12 at 11:23
  • @EricLippert doesn't code like `a.b.c.d` violates law of Demeter and push programmers to write coupled train wrecks, exposing internals of dependencies? Its often hard to understand such code and its hard to test. – Sergey Berezovskiy Apr 28 '12 at 09:57
  • 28
    @lazyberezovsky: I've never understood the so-called "law" of Demeter; first of all, it appears to more accurately be called "The Suggestion of Demeter". And second, the result of taking "only one member access" to its logical conclusion is "God objects" where every object is required to do everything for every client, rather than being able to hand out objects that know how to do what the client wants. I prefer the exact opposite of the law of demeter: every object solves a small number of problems well, and one of those solutions can be "here's another object that solves your problem better" – Eric Lippert Apr 28 '12 at 14:59
  • @EricLippert well, maybe. But from my small experience God Objects are usually result of assigning too many responsibilities to one class.. – Sergey Berezovskiy Apr 28 '12 at 21:05
  • 6
    I've never been sold on the "Law of Demeter". In particular, I think the "one-dot" rule of thumb is stupid, precisely for the reasons Eric mentions. e.g., I've seen some Demeter zealots create horrid classes with four or five times as many members that just pass through to child objects (to avoid forcing clients to use a second dot) as they have members providing class-relevant services. That's an anti-pattern. Perhaps a misunderstanding of LoD as well? But if well-intentioned devs are led to create crap by the principle, perhaps the princple itself needs refinement. – Greg D Apr 28 '12 at 22:06
  • The new operation Eric spoke of in his answer may be coming soon: http://coolthingoftheday.blogspot.co.uk/2014/02/for-c-aka-c-might-be-getting-object.html – mwilson Feb 27 '14 at 14:53
  • This feature is now 'under review' as of feb 25th 2014 : http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/3990187-add-operator-to-c-?tracking_code=c7847708c234b1da17b8d1c85637c827 – Jochen van Wylick Mar 01 '14 at 06:50
  • Is this in the Roslyn release that come out last week or are you talking about a future Roslyn release? – Rush Frisby Apr 10 '14 at 17:05
  • Why you don't have an operator to check if a variable is not null then assign its value to another variable, otherwise keep the current value of that varaible. Something like x = y ?? y.value; – Ahmad Jan 01 '16 at 12:20
  • is there any performance hit from using the ?.Invoke syntax instead of checking for null and calling the delegate directly? – mcmillab Jun 15 '17 at 00:22
  • @mcmillab Write the code both ways. Run it both ways. Now you know which one is faster! – Eric Lippert Jun 15 '17 at 00:49
  • @EricLippert understood and I agree.... however that is mostly a sensible approach where the performance of one vs the other may vary due to your situation. I would have thought in this case it's either *always* exactly the same, or *always* slower? – mcmillab Jun 15 '17 at 01:45
  • 1
    @mcmillab You are proposing a hypothesis. Now design an empirical test which will confirm or falsify your hypothesis, perform your experiment, and publish your results. Performance questions can be answered by science or by guessing, but only one of those gives reliable answers. – Eric Lippert Jun 15 '17 at 02:04
  • 1
    But my hypothesis is that something is always the case, which is not possible to test. Someone however may know the answer... Perhaps the compiler inlines to exactly the same code. Also there's no point everybody running the same test if the answer is known – mcmillab Jun 15 '17 at 02:16
  • Is there something like this that works with dynamic (ExpandoObject) ? – Ewerton Oct 17 '17 at 11:52
  • @Ewerton: That sounds like an excellent question to post on StackOverflow *as a question*. – Eric Lippert Oct 17 '17 at 14:16
  • @EricLippert Done! https://stackoverflow.com/questions/46790684/is-there-a-way-to-perform-a-chained-null-check-in-a-dynamic-expando – Ewerton Oct 17 '17 at 16:21
28

I got inspired by this question to try and find out how this kind of deep null checking can be done with an easier / prettier syntax using expression trees. While I do agree with the answers stating that it might be a bad design if you often need to access instances deep in the hierarchy, I also do think that in some cases, such as data presentation, it can be very useful.

So I created an extension method, that will allow you to write:

var berries = cake.IfNotNull(c => c.Frosting.Berries);

This will return the Berries if no part of the expression is null. If null is encountered, null is returned. There are some caveats though, in the current version it will only work with simple member access, and it only works on .NET Framework 4, because it uses the MemberExpression.Update method, which is new in v4. This is the code for the IfNotNull extension method:

using System;
using System.Collections.Generic;
using System.Linq.Expressions;

namespace dr.IfNotNullOperator.PoC
{
    public static class ObjectExtensions
    {
        public static TResult IfNotNull<TArg,TResult>(this TArg arg, Expression<Func<TArg,TResult>> expression)
        {
            if (expression == null)
                throw new ArgumentNullException("expression");

            if (ReferenceEquals(arg, null))
                return default(TResult);

            var stack = new Stack<MemberExpression>();
            var expr = expression.Body as MemberExpression;
            while(expr != null)
            {
                stack.Push(expr);
                expr = expr.Expression as MemberExpression;
            } 

            if (stack.Count == 0 || !(stack.Peek().Expression is ParameterExpression))
                throw new ApplicationException(String.Format("The expression '{0}' contains unsupported constructs.",
                                                             expression));

            object a = arg;
            while(stack.Count > 0)
            {
                expr = stack.Pop();
                var p = expr.Expression as ParameterExpression;
                if (p == null)
                {
                    p = Expression.Parameter(a.GetType(), "x");
                    expr = expr.Update(p);
                }
                var lambda = Expression.Lambda(expr, p);
                Delegate t = lambda.Compile();                
                a = t.DynamicInvoke(a);
                if (ReferenceEquals(a, null))
                    return default(TResult);
            }

            return (TResult)a;            
        }
    }
}

It works by examining the expression tree representing your expression, and evaluating the parts one after the other; each time checking that the result is not null.

I am sure this could be extended so that other expressions than MemberExpression is supported. Consider this as proof-of-concept code, and please keep in mind that there will be a performance penalty by using it (which will probably not matter in many cases, but don't use it in a tight loop :-) )

driis
  • 161,458
  • 45
  • 265
  • 341
  • I'm impressed by your lambda skills :) the syntax does however seem to be a tad bit more complex than one would like, atleast for the if-statement scenario – Homde Jan 17 '10 at 20:37
  • Cool, but it runs like 100x more code than an if..&&. It's only worthwhile if it still compiles down to an if..&&. – Monstieur Jan 08 '13 at 10:46
  • 1
    Ah and then I saw `DynamicInvoke` there. I religiously avoid that :) – nawfal Oct 11 '13 at 07:47
24

I've found this extension to be quite useful for deep nesting scenarios.

public static R Coal<T, R>(this T obj, Func<T, R> f)
    where T : class
{
    return obj != null ? f(obj) : default(R);
}

It's an idea I derrived from the null coalescing operator in C# and T-SQL. The nice thing is that the return type is always the return type of the inner property.

That way you can do this:

var berries = cake.Coal(x => x.frosting).Coal(x => x.berries);

...or a slight variation of the above:

var berries = cake.Coal(x => x.frosting, x => x.berries);

It's not the best syntax I know, but it does work.

John Leidegren
  • 59,920
  • 20
  • 131
  • 152
  • Why "Coal", that looks a extremely creepy. ;) However, your sample would fail if frosting were null. Should've looked like so: var berries = cake.NullSafe(c => c.Frosting.NullSafe(f => f.Berries)); – Robert Giesecke Feb 08 '10 at 05:49
  • Oh, but you're implying that the second argument is not a call to Coal which it of course has to be. It just a convenient alteration. The selector (x => x.berries) is passed to a Coal call inside the Coal method that takes two arguments. – John Leidegren Feb 22 '10 at 10:02
  • The name coalescing or coalesce was taken from T-SQL, that's where I first got the idea. IfNotNull implies that something takes place if not null, however what that is, is not explained by the IfNotNull method call. Coal is indeed an odd name, but this is in deed an odd method worth taking notice of. – John Leidegren Feb 22 '10 at 10:04
  • The best literally name for this would be something like "ReturnIfNotNull" or "ReturnOrDefault" – John Leidegren Feb 22 '10 at 10:05
  • @flq +1... in our project it's _also_ called IfNotNull :) – Marc Sigrist May 15 '12 at 12:29
  • @John, I was going for something like this, but doesn't `default(R)` return null if R is a reference type? The only way I found around this is to return `new R()` but that seems kind of inefficient. – AaronLS Jul 06 '12 at 19:31
  • Well, `R` is the type of the return value of the member accessor `f` passed. It's not constrained to anything in particular. `R` can be a value type. The point is here is that instead of throwing an `NullReferenceException` return the **default** value of the inner most property. Whatever the return value is, it's just another value that has to be dealt with accordingly. We're not going to prevent anyone from having to write `if != null` that would be rather unnecessary as the if-statement really is shorter than this and less mysterious. – John Leidegren Jul 13 '12 at 11:39
  • We're strictly talking about reaching deep into the object graph and getting at some value which may or may not be there. – John Leidegren Jul 13 '12 at 11:40
16

Besides violating the Law of Demeter, as Mehrdad Afshari has already pointed out, it seems to me you need "deep null checking" for decision logic.

This is most often the case when you want to replace empty objects with default values. In this case you should consider implementing the Null Object Pattern. It acts as a stand-in for a real object, providing default values and "non-action" methods.

Johannes Rudolph
  • 35,298
  • 14
  • 114
  • 172
10

Update: Starting with Visual Studio 2015, the C# compiler (language version 6) now recognizes the ?. operator, which makes "deep null checking" a breeze. See this answer for details.

Apart from re-designing your code, like this deleted answer suggested, another (albeit terrible) option would be to use a try…catch block to see if a NullReferenceException occurs sometime during that deep property lookup.

try
{
    var x = cake.frosting.berries.loader;
    ...
}
catch (NullReferenceException ex)
{
    // either one of cake, frosting, or berries was null
    ...
}

I personally wouldn't do this for the following reasons:

  • It doesn't look nice.
  • It uses exception handling, which should target exceptional situations and not something that you expect to happen often during the normal course of operation.
  • NullReferenceExceptions should probably never be caught explicitly. (See this question.)

So is it possible using some extension method or would it be a language feature, [...]

This would almost certainly have to be a language feature (which is available in C# 6 in the form of the .? and ?[] operators), unless C# already had more sophisticated lazy evaluation, or unless you want to use reflection (which probably also isn't a good idea for reasons of performance and type-safety).

Since there's no way to simply pass cake.frosting.berries.loader to a function (it would be evaluated and throw a null reference exception), you would have to implement a general look-up method in the following way: It takes in an objects and the names of properties to look up:

static object LookupProperty( object startingPoint, params string[] lookupChain )
{
    // 1. if 'startingPoint' is null, return null, or throw an exception.
    // 2. recursively look up one property/field after the other from 'lookupChain',
    //    using reflection.
    // 3. if one lookup is not possible, return null, or throw an exception.
    // 3. return the last property/field's value.
}

...

var x = LookupProperty( cake, "frosting", "berries", "loader" );

(Note: code edited.)

You quickly see several problems with such an approach. First, you don't get any type safety and possible boxing of property values of a simple type. Second, you can either return null if something goes wrong, and you will have to check for this in your calling function, or you throw an exception, and you're back to where you started. Third, it might be slow. Fourth, it looks uglier than what you started with.

[...], or is it just a bad idea?

I'd either stay with:

if (cake != null && cake.frosting != null && ...) ...

or go with the above answer by Mehrdad Afshari.


P.S.: Back when I wrote this answer, I obviously didn't consider expression trees for lambda functions; see e.g. @driis' answer for a solution in this direction. It's also based on a kind of reflection and thus might not perform quite as well as a simpler solution (if (… != null & … != null) …), but it may be judged nicer from a syntax point-of-view.

Community
  • 1
  • 1
stakx - no longer contributing
  • 83,039
  • 20
  • 168
  • 268
  • 2
    I Don't know why this was downvoted, I did an upvote for balance: Answer is correct and brings in a new aspect (and explicitely mentions the drawbacks of this solution...) – MartinStettner Jan 17 '10 at 10:56
  • where is "the above answer by Mehrdad Afshari"? – Marson Mao Jul 22 '15 at 06:23
  • 1
    @MarsonMao: That answer has been deleted in the meantime. (You're still able to read it if your SO rank is sufficiently high.) Thanks for pointing out my mistake: I should refer to other answers using a hyperlink, not using words like "see above" / "see below" (since answers don't appear in a fixed order). I've updated my answer. – stakx - no longer contributing Jul 23 '15 at 06:15
5

While driis' answer is interesting, I think it's a bit too expensive performance wise. Rather than compiling many delegates, I'd prefer to compile one lambda per property path, cache it and then reinvoke it many types.

NullCoalesce below does just that, it returns a new lambda expression with null checks and a return of default(TResult) in case any path is null.

Example:

NullCoalesce((Process p) => p.StartInfo.FileName)

Will return an expression

(Process p) => (p != null && p.StartInfo != null ? p.StartInfo.FileName : default(string));

Code:

    static void Main(string[] args)
    {
        var converted = NullCoalesce((MethodInfo p) => p.DeclaringType.Assembly.Evidence.Locked);
        var converted2 = NullCoalesce((string[] s) => s.Length);
    }

    private static Expression<Func<TSource, TResult>> NullCoalesce<TSource, TResult>(Expression<Func<TSource, TResult>> lambdaExpression)
    {
        var test = GetTest(lambdaExpression.Body);
        if (test != null)
        {
            return Expression.Lambda<Func<TSource, TResult>>(
                Expression.Condition(
                    test,
                    lambdaExpression.Body,
                    Expression.Default(
                        typeof(TResult)
                    )
                ),
                lambdaExpression.Parameters
            );
        }
        return lambdaExpression;
    }

    private static Expression GetTest(Expression expression)
    {
        Expression container;
        switch (expression.NodeType)
        {
            case ExpressionType.ArrayLength:
                container = ((UnaryExpression)expression).Operand;
                break;
            case ExpressionType.MemberAccess:
                if ((container = ((MemberExpression)expression).Expression) == null)
                {
                    return null;
                }
                break;
            default:
                return null;
        }
        var baseTest = GetTest(container);
        if (!container.Type.IsValueType)
        {
            var containerNotNull = Expression.NotEqual(
                container,
                Expression.Default(
                    container.Type
                )
            );
            return (baseTest == null ?
                containerNotNull :
                Expression.AndAlso(
                    baseTest,
                    containerNotNull
                )
            );
        }
        return baseTest;
    }
Double Down
  • 898
  • 6
  • 13
4

One option is to use the Null Object Patten, so instead of having null when you don’t have a cake, you have a NullCake that returns a NullFosting etc. Sorry I am not very good at explaining this but other people are, see

Ian Ringrose
  • 51,220
  • 55
  • 213
  • 317
3

I too have often wished for a simpler syntax! It gets especially ugly when you have method-return-values that might be null, because then you need extra variables (for example: cake.frosting.flavors.FirstOrDefault().loader)

However, here's a pretty decent alternative that I use: create an Null-Safe-Chain helper method. I realize that this is pretty similar to @John's answer above (with the Coal extension method) but I find it's more straightforward and less typing. Here's what it looks like:

var loader = NullSafe.Chain(cake, c=>c.frosting, f=>f.berries, b=>b.loader);

Here's the implementation:

public static TResult Chain<TA,TB,TC,TResult>(TA a, Func<TA,TB> b, Func<TB,TC> c, Func<TC,TResult> r) 
where TA:class where TB:class where TC:class {
    if (a == null) return default(TResult);
    var B = b(a);
    if (B == null) return default(TResult);
    var C = c(B);
    if (C == null) return default(TResult);
    return r(C);
}

I also created several overloads (with 2 to 6 parameters), as well as overloads that allow the chain to end with a value-type or default. This works really well for me!

Scott Rippey
  • 15,614
  • 5
  • 70
  • 85
1

There is Maybe codeplex project that Implements Maybe or IfNotNull using lambdas for deep expressions in C#

Example of use:

int? CityId= employee.Maybe(e=>e.Person.Address.City);

The link was suggested in a similar question How to check for nulls in a deep lambda expression?

Community
  • 1
  • 1
Michael Freidgeim
  • 26,542
  • 16
  • 152
  • 170
1

As suggested in John Leidegren's answer, one approach to work-around this is to use extension methods and delegates. Using them could look something like this:

int? numberOfBerries = cake
    .NullOr(c => c.Frosting)
    .NullOr(f => f.Berries)
    .NullOr(b => b.Count());

The implementation is messy because you need to get it to work for value types, reference types and nullable value types. You can find a complete implementation in Timwi's answer to What is the proper way to check for null values?.

Community
  • 1
  • 1
Sam
  • 40,644
  • 36
  • 176
  • 219
1

Or you may use reflection :)

Reflection function:

public Object GetPropValue(String name, Object obj)
    {
        foreach (String part in name.Split('.'))
        {
            if (obj == null) { return null; }

            Type type = obj.GetType();
            PropertyInfo info = type.GetProperty(part);
            if (info == null) { return null; }

            obj = info.GetValue(obj, null);
        }
        return obj;
    }

Usage:

object test1 = GetPropValue("PropertyA.PropertyB.PropertyC",obj);

My Case(return DBNull.Value instead of null in reflection function):

cmd.Parameters.AddWithValue("CustomerContactEmail", GetPropValue("AccountingCustomerParty.Party.Contact.ElectronicMail.Value", eInvoiceType));
heybeliman
  • 11
  • 1
1

Try this code:

    /// <summary>
    /// check deep property
    /// </summary>
    /// <param name="obj">instance</param>
    /// <param name="property">deep property not include instance name example "A.B.C.D.E"</param>
    /// <returns>if null return true else return false</returns>
    public static bool IsNull(this object obj, string property)
    {
        if (string.IsNullOrEmpty(property) || string.IsNullOrEmpty(property.Trim())) throw new Exception("Parameter : property is empty");
        if (obj != null)
        {
            string[] deep = property.Split('.');
            object instance = obj;
            Type objType = instance.GetType();
            PropertyInfo propertyInfo;
            foreach (string p in deep)
            {
                propertyInfo = objType.GetProperty(p);
                if (propertyInfo == null) throw new Exception("No property : " + p);
                instance = propertyInfo.GetValue(instance, null);
                if (instance != null)
                    objType = instance.GetType();
                else
                    return true;
            }
            return false;
        }
        else
            return true;
    }
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
JKSUN
  • 11
  • 1
0

I slightly modified the code from here to make it work for the question asked:

public static class GetValueOrDefaultExtension
{
    public static TResult GetValueOrDefault<TSource, TResult>(this TSource source, Func<TSource, TResult> selector)
    {
        try { return selector(source); }
        catch { return default(TResult); }
    }
}

And yes, this is probably not the optimal solution due to try/catch performance implications but it works :>

Usage:

var val = cake.GetValueOrDefault(x => x.frosting.berries.loader);
Community
  • 1
  • 1
kaptan
  • 3,060
  • 5
  • 34
  • 46
0

Where you need to achieve this, do this:

Usage

Color color = someOrder.ComplexGet(x => x.Customer.LastOrder.Product.Color);

or

Color color = Complex.Get(() => someOrder.Customer.LastOrder.Product.Color);

Helper class implementation

public static class Complex
{
    public static T1 ComplexGet<T1, T2>(this T2 root, Func<T2, T1> func)
    {
        return Get(() => func(root));
    }

    public static T Get<T>(Func<T> func)
    {
        try
        {
            return func();
        }
        catch (Exception)
        {
            return default(T);
        }
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jay Byford-Rew
  • 5,736
  • 1
  • 35
  • 36
0

I posted this last night and then a friend pointed me to this question. Hope it helps. You can then do something like this:

var color = Dis.OrDat<string>(() => cake.frosting.berries.color, "blue");


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;

namespace DeepNullCoalescence
{
  public static class Dis
  {
    public static T OrDat<T>(Expression<Func><T>> expr, T dat)
    {
      try
      {
        var func = expr.Compile();
        var result = func.Invoke();
        return result ?? dat; //now we can coalesce
      }
      catch (NullReferenceException)
      {
        return dat;
      }
    }
  }
}

Read the full blog post here.

The same friend also suggested that you watch this.

Tyler Jensen
  • 811
  • 6
  • 12
-4

I like approach taken by Objective-C:

"The Objective-C language takes another approach to this problem and does not invoke methods on nil but instead returns nil for all such invocations."

if (cake.frosting.berries != null) 
{
    var str = cake.frosting.berries...;
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
  • 1
    what another language does (and your opinion of it) is almost entirely irrelevant to making it work in C#. It doesn't help anyone to solve their C# problem – ADyson Oct 01 '18 at 13:29