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
Is There a Reason Image.Fromfile Throws an Outofmemoryexception for an Invalid Image Format
How to Remove Whitespace on Merge
Unzip Files Programmatically in .Net
Unauthorised Webapi Call Returning Login Page Rather Than 401
How to Return a Value from a Form in C#
How to Copy Data to Clipboard in C#
What Strategies and Tools Are Useful for Finding Memory Leaks in .Net
How to Unserialize PHP Serialized Array/Variable/Class and Return Suitable Object in C#
How Do Prefix (++X) and Postfix (X++) Operations Work
Marshal C++ Struct Array into C#
Kill Some Processes by .Exe File Name
Remove HTML Tags from String Including &Nbsp in C#
Asp.Net: Invalid Postback or Callback Argument
Insert Entire Datatable into Database at Once Instead of Row by Row
Using' Statement VS 'Try Finally'