Null conditional operator not working with null types?

I am writing a piece of code in C # 6 and for some strange reason this works

var value = objectThatMayBeNull?.property; 

but this is not so:

 int value = nullableInt?.Value; 

Doesn't work I mean that I get a compilation error saying Cannot resolve symbol 'Value' . Any idea why the conditional operator is null ?. does not work?

+45
c # null-coalescing-operator
Aug 04 '15 at 13:59 on
source share
7 answers

Well, I thought a bit and experienced. Here's what happens:

 int value = nullableInt?.Value; 

Gives this compilation error message:

The type 'int' does not contain a definition for `Value '

Does that mean ? "converts" int? into the actual value of int . This is actually the same as:

 int value = nullableInt ?? default(int); 

The result is an integer that does not have Value , obviously.

Ok, can this help?

 int value = nullableInt?; 

No, this syntax is not allowed.

So what then? Just keep using .GetValueOrDefault() for this case.

 int value = nullableInt.GetValueOrDefault(); 
+20
Aug 04 '15 at 2:03
source share
โ€” -

The reason for this is that accessing a value using an operator with a null condition would be pointless:

  • When you apply x?.p , where p is the type of the value with a zero value of T , the result is of type T? . Similarly, the result of the nullableInt?.Value operation must be zero.
  • When your Nullable<T> matters, the result of nullableInt?.Value will be the same as the value itself
  • If your Nullable<T> does not matter, the result will be null , which again matches the value itself.

Although it makes no sense to access Value with the ?. Operator ?. , it makes sense to access other properties of value types with a zero value. The operator works with null value types and reference types, so these two implementations produce the same behavior:

 class PointClass { public int X { get; } public int Y { get; } public PointClass(int x, int y) { X = x; Y = y; } } struct PointStruct { public int X { get; } public int Y { get; } public PointStruct(int x, int y) { X = x; Y = y; } } ... PointClass pc = ... PointStruct? ps = ... int? x = pc?.X; int? y = ps?.Y; 

In the case of a nullable struct operator allows you to access a property of the base type PointStruct , and it adds a null value to the result in the same way as for non-empty properties of the reference type PointClass .

+16
Aug 04 '15 at 14:06
source share

As for types with a null value, the ?. Operator ?. says if not null, use the wrapped value . So, for a nullable int, if the nullable value is 8 , the result is ?. will be 8 , not a nullable value containing 8 . Since Value not an int property, you get an error message.

So, an example of trying to use the Value property quite rightly fails, but the following will work,

var x = nullableInt?.ToString();

Consider the null-coalescing operator, ?? .

var x = nullableInt ?? 0;

Here the statement says, if null, return 0, otherwise return the value inside the nullable , which in this case is int . The operator ?. performs similar actions to retrieve content with a null value.

In your specific example, should you use the ?? operator and the corresponding default, not the ?. operator ?. .

+5
Aug 04 '15 at 14:05
source share

I basically agree with the other answers. I just hoped that the observed behavior could be backed up by some kind of official documentation.

Since I cannot find the C # 6.0 specification anywhere (not yet?), The closest to the โ€œdocumentationโ€ is the C # Language Design Notes for February 3, 2014 . Assuming that the information found there still reflects the current state of affairs, here are the relevant parts that formally explain the observed behavior.

The semantics are similar to how to apply a ternary operator to checking for null equality, a null literal, and an operator not subject to a query query, except that the expression is evaluated only once:

 e?.m(โ€ฆ) => ((e == null) ? null : e0.m(โ€ฆ)) e?.x => ((e == null) ? null : e0.x) e?.$x => ((e == null) ? null : e0.$x) e?[โ€ฆ] => ((e == null) ? null : e0[โ€ฆ]) 

Where e0 matches e , except that e is NULL, in this case e0 is e.Value .

Applying this last rule to:

 nullableInt?.Value 

... the semantically equivalent expression becomes:

 ((nullableInt == null) ? null : nullableInt.Value.Value) 

It is clear that nullableInt.Value.Value cannot compile and what you have observed.

Regarding why the constructive decision was made to apply this special rule to types with null type, I think the dasblinkenlight answer covers this beautifully, so I wonโ€™t repeat it here.




In addition, I should mention this, even if, presumably, we did not have this special rule for types with a null value, and the expression nullableInt?.Value executed and was carried out as you originally thought ...

 // let pretend that it actually gets converted to this... ((nullableInt == null) ? null : nullableInt.Value) 

the following statement from your question will be invalid and will result in a compilation error:

 int value = nullableInt?.Value; // still would not compile 

The reason it won't work anyway is because the expression type nullableInt?.Value will be int? , not int . So you will need to change the type of the variable value to int? .

This is also officially described in C # Language Design Notes for February 3, 2014 :

The type of result depends on the type T right side of the base operator:

  • If T is (as you know) a reference type, the type of the expression is T
  • If T is (as you know) a type of non-empty value, is the type of expression equal to T?
  • If T is (as you know) a type with a zero value, the type of the expression is T
  • Otherwise (that is, if it is not known whether T reference or a value type), the expression is a compile-time error.

But if you are then forced to write the following to compile it:

 int? value = nullableInt?.Value; 

... then this seems rather pointless, and it will not differ from simple:

 int? value = nullableInt; 

As others pointed out, in your case, you probably wanted to use a zero-coalescent operator ?? , but not an operator with a null condition ?. .

+4
Aug 08 '15 at 5:38
source share

An operator with a null condition also expands a variable with a null value. So, after the "?". operator, the Value property is no longer required.

I wrote a post detailing how I came across this. If you are interested,

http://www.ninjacrab.com/2016/09/11/c-how-the-null-conditional-operator-works-with-nullable-types/

0
11 Sep '16 at 9:29
source share

Just because (based on sstan's answer above)

 var value = objectThatMayBeNull?.property; 

evaluated by the compiler as

 var value = (objectThatMayBeNull == null) ? null : objectThatMayBeNull.property 

and

 int value = nullableInt?.Value; 

as

 int value = (nullableInt == null) ? null : nullableInt.Value.Value; 

when nullableInt.Value.Value is Cannot resolve symbol 'Value' syntax error!

0
06 Oct '16 at 11:12
source share

int does not have a Value property.

Consider:

 var value = obj?.Property 

It is equivalent to:

 value = obj == null ? null : obj.Property; 

Does this make no sense with int and therefore not with int? through ?.

Old GetValueOrDefault() makes sense with int? .

Or, if so, since ? should return something null, simply:

 int? value = nullableInt; 
-one
Aug 04 '15 at 14:02
source share



All Articles