4

var a = b?.c.d;

Shouldn't this expression always give a compile error? If b is null, the null value is propagated through so c will also be null and thus also need this operator. In my understanding usage of this operator in an expression spreads viral.

But neither Visual Studio 2015 nor Resharper says anything to me, am I missing something here?

11
  • Why would it be a compiler error? If b is null then the expression evaluates to null. If it isn't then the expression returns the result of b.c.d. Commented Mar 31, 2017 at 14:03
  • 1
    No, if b already is null, c isn´t evaluated at all, making a simply null. Commented Mar 31, 2017 at 14:03
  • I don't understand the question; if b is null, the expression is not evaluated furter, but yields null, so there is no chance anything happens to c. Commented Mar 31, 2017 at 14:04
  • What compiler error are you expecting to be generated? Commented Mar 31, 2017 at 14:08
  • 1
    Were you maybe thinking of var a = (b?.c).d;? Commented Mar 31, 2017 at 14:11

4 Answers 4

4

The operator is just syntactic sugar for this:

MyType a = b == null ? 
    null: 
    b.c.d;

Why this should throw a compile-error is unclear to me.

If b is null, the null value is propagated through so c will also be null and thus also need this operator

This isn´t true. Actually when b is null c doesn´t even exist as there´s no instance on which that member could exist. So in short the operator just returns null and omits evaluating c or even d any further.

Sign up to request clarification or add additional context in comments.

4 Comments

That's not a valid conversion. a is always assigned a new value, although that value might be null.
var a = (b == null) ? null : b.c.d;
Also note that b is not actually evaluated multiple times, so your sugar isn't right for that reason either, although it's closer now.
An example to illustration the latest comment by @Servy could be if b was defined as in: class CurrentClass { static bool wasCalledBefore; static B { get { if(wasCalledBefore) { return null; } wasCalledBefore = true; return new B { c = new C { d = new D(), }, }; } } }
0

This operator does short circuit and returns null in case of b is null.

Comments

0
var a = b == null ? null : b.c.d

This is what that statement would look like in the old way, the ?. operator doesn't look deeper when what is before it is null, it just returns null, you WILL however get an error where b is defined but b.c == null since you didn't write as var a = b?.c?.d.

Comments

0

Note that:

var a1 = b?.c.d;

is entirely different from:

var a2 = (b?.c).d;

It is not very easy to explain in short how the unary operator ?. works (yes, unary!). But the idea is that the rest of the "chain" of "operations" is skipped if the expression before ?. is null.

So for a1, you get a null of the compile-time type carried by member d (or Nullable<> of that type if necessary) whenever b happens to be null. When b happens to be non-null, you get the same as b.c.d which may fail if b.c is null.

But a2 is quite different. It will always blow up if b is null, because then the parenthesis (b?.c) will be a null reference, and the next . operator will lead to NullReferenceException. (I am assuming here that c has a reference-type at compile-time.)

So do not think there is a kind of "left-associativity" that makes b?.c.d equivalent to (b?.c).d!


You can find a link to the preliminary C# Language Specification in this answer in another thread; they mention Null-conditional operator as an unary operator in § 7.7.1.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.