Nullable Type Issue with : Conditional Operator

Nullable type issue with ?: Conditional Operator

The compiler is telling you that it doesn't know how convert null into a DateTime.

The solution is simple:

DateTime? foo;
foo = true ? (DateTime?)null : new DateTime(0);

Note that Nullable<DateTime> can be written DateTime? which will save you a bunch of typing.

Conditional Operator ?: with Nullable type Casting

null can represent any object-based datatype. You need to cast null as a datatype so it know what you are talking about.

int? x = (value.HasValue) ? value.Value : (int?)null;

I know, it sounds a bit strange.


To answer the questions in the comments:

Why is it not implicit though?

Yeah, I get that. But why do I not have to cast it in a If Else block?

Let's walk through the code.

Your else statement looks like this:

else x = null;

This means you are assigning the value of null to x. This is valid, because x is a int?, which takes nulls.

The difference comes when you have the ternary operator. It says: "assign the value of the operator into x". The question (and the reason for your error) is, what datatype is the result of the ternary operator?

From your code, you can't be sure, and the compiler throws its hands up.

int? x = (value.HasValue) ? value.Value : null;
// int? bool int ??

What datatype is null? You are quick to say "well it's a int?, because the other side is a int and the result is a int?". The problem is, what about the following:

string a = null;
bool? b = null;
SqlConnectionStringBuilder s = null;

This is also valid, which means null can be used for any object-based datatype. This is why you have to explicitly cast null as the type you want to use, because it can be used for anything!


Another explanation (and possible more accurate):

You can't have an implicit cast between a nullable and a non-nullable value.

int is not-nullable (it's a structure), where null is. This is why in Habib's answer you can put the cast on either the left or right side.

Nullable types and the ternary operator: why is `? 10 : null` forbidden?

The compiler first tries to evaluate the right-hand expression:

GetBoolValue() ? 10 : null

The 10 is an int literal (not int?) and null is, well, null. There's no implicit conversion between those two hence the error message.

If you change the right-hand expression to one of the following then it compiles because there is an implicit conversion between int? and null (#1) and between int and int? (#2, #3).

GetBoolValue() ? (int?)10 : null    // #1
GetBoolValue() ? 10 : (int?)null // #2
GetBoolValue() ? 10 : default(int?) // #3

null conditional operator not working with nullable types?

Okay, I have done some thinking and testing. This is what happens:

int value = nullableInt?.Value;

Gives this error message when compiling:

Type 'int' does not contain a definition for `Value'

That means that ? 'converts' the int? into the actual int value. This is effectively the same as:

int value = nullableInt ?? default(int);

The result is an integer, which doesn't have a Value, obviously.

Okay, might this help?

int value = nullableInt?;

No, that syntax isn't allowed.

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

int value = nullableInt.GetValueOrDefault();

Conditional operator assignment with Nullable value types?

The problem occurs because the conditional operator doesn't look at how the value is used (assigned in this case) to determine the type of the expression -- just the true/false values. In this case, you have a null and an Int32, and the type can not be determined (there are real reasons it can't just assume Nullable<Int32>).

If you really want to use it in this way, you must cast one of the values to Nullable<Int32> yourself, so C# can resolve the type:

EmployeeNumber =
string.IsNullOrEmpty(employeeNumberTextBox.Text)
? (int?)null
: Convert.ToInt32(employeeNumberTextBox.Text),

or

EmployeeNumber =
string.IsNullOrEmpty(employeeNumberTextBox.Text)
? null
: (int?)Convert.ToInt32(employeeNumberTextBox.Text),

Why doesn't the conditional operator correctly allow the use of null for assignment to nullable types?

This doesn't work because the compiler will not insert an implicit conversion on both sides at once, and null requires an implicit conversion to become a nullable type.

Instead, you can write

task.ActualEndDate = TextBoxActualEndDate.Text != "" ? 
DateTime.Parse(TextBoxActualEndDate.Text) : new DateTime?();

This only requires one implicit conversion (DateTime to DateTime?).

Alternatively, you can cast either left side:

task.ActualEndDate = TextBoxActualEndDate.Text != "" ? 
(DateTime?)DateTime.Parse(TextBoxActualEndDate.Text) : null;

This also requires only one implicit conversion.

Null Conditional Operator with method .Value from Nullable structure

The variable?.Member on a nullable type of a value type T actually translates to a function roughly like

if (variable.HasValue)
return variable.GetValueOrDefault().Member;
else
return null;

variable.GetValueOrDefault() is of the type T, not Nullable<T>. Only Nullable<T> has a member Value (unless it is your own struct that contains a member Value, but e.g. int from your code does not).

In C# why can't a conditional operator implicitly cast to a nullable type

The relevant section of the C# 3.0 spec is 7.13, the conditional operator:

The second and third operands of the ?: operator control the type of the conditional expression. Let X and Y be the types of the second and third operands. Then,

If X and Y are the same type, then this is the type of the conditional
Otherwise, if an implicit conversion (§6.1) exists from X to Y, but not from Y to X, then Y is the type of the conditional expression.
Otherwise, if an implicit conversion (§6.1) exists from Y to X, but not from X to Y, then X is the type of the conditional expression.
Otherwise, no expression type can be determined, and a compile-time error occurs.

How to use Conditional Operation with Nullable Int

Yes - the compiler can't find an appropriate type for the conditional expression. Ignore the fact that you're assigning it to an int? - the compiler doesn't use that information. So the expression is:

(this.Policy == null) ? null : 1;

What's the type of this expression? The language specification states that it has to be either the type of the second operand or that of the third operand. null has no type, so it would have to be int (the type of the third operand) - but there's no conversion from null to int, so it fails.

Cast either of the operands to int? and it will work, or use another way of expessing the null value - so any of these:

(this.Policy == null) ? (int?) null : 1;

(this.Policy == null) ? null : (int?) 1;

(this.Policy == null) ? default(int?) : 1;

(this.Policy == null) ? new int?() : 1;

I agree it's a slight pain that you have to do this.


From the C# 3.0 language specification section 7.13:

The second and third operands of the
?: operator control the type of the
conditional expression. Let X and Y be
the types of the second and third
operands. Then,

  • If X and Y are the same type, then this is the type of the conditional
    expression.

  • Otherwise, if an implicit conversion (§6.1) exists from X to Y, but not
    from Y to X, then Y is the type of the
    conditional expression.

  • Otherwise, if an implicit conversion (§6.1) exists from Y to X, but not
    from X to Y, then X is the type of the
    conditional expression.

  • Otherwise, no expression type can be determined, and a compile-time error
    occurs.



Related Topics



Leave a reply



Submit