Reputation: 7145
As you might know, DateTime?
does not have a parametrized ToString
(for the purposes of formatting the output), and doing something like
DateTime? dt = DateTime.Now;
string x;
if(dt != null)
x = dt.ToString("dd/MM/yyyy");
will throw
No overload for method 'ToString' takes 1 arguments
But, since C# 6.0 and the Elvis (?.
) operator, the above code can be replaced with
x = dt?.ToString("dd/MM/yyyy");
which.... works! Why?
Upvotes: 29
Views: 3263
Reputation: 10287
Short answer:
DateTime?
is only a sweet syntax for Nullable<DateTime>
which doesn't contain DateTime
's properties and method while the Elvis operator works on the not-Nullable Nullable<DateTime>.Value
.
Explanation:
The following code:
DateTime? dt = DateTime.Now;
string x;
if (dt != null)
x = dt?.ToString("dd/MM/yyyy");
When decompiles as C# 5.0
yields the following result:
DateTime? nullable = new DateTime?(DateTime.Now);
if (nullable.HasValue)
{
string str = nullable.HasValue ? nullable.GetValueOrDefault().ToString("dd/MM/yyyy") : null;
}
Side note: the string
seems declared inside the if
is irrelevant because of hoisting at the MSIL
level, and since the value is not used later on the decompiler shows it as if it was declared inside that if
scope.
As you see, and since DateTime?
is only a sweet syntax for Nullable<DateTime>
, C#
has a specific reference for Nullable<T>
s with the Elvis operator, making its return value the non-nullable T itself.
The result of the whole Elvis operator
must be Nullable
therefore, if you wanted to receive a non-string
value it would have to be either Nullable<T>
or a ReferenceType
but this doesn't change the fact that if the operator has managed to get the Nullable<DateTime>
value itself - the returned DateTime
is not Nullable<DateTime>
anymore.
Upvotes: 14
Reputation: 8359
Considering:
DateTime? dt = DateTime.Now;
string x;
if(dt != null)
x = dt.ToString("dd/MM/yyyy");
Here dt
is a DateTime?
or Nullable<DateTime>
witch is not IFormatable
and don't have a ToString(string format)
method.
So it throw.
Now considering:
x = dt?.ToString("dd/MM/yyyy");
The ?.
is a syntactic sugar for:
dt.HasValue ? dt.Value.ToString("dd/MM/yyyy"): null
Here dt.Value
is a DateTime
witch is IFormatable
and have a ToString(string format)
method.
Finally the good way to write the first code in C# 5.0 is:
DateTime? dt = DateTime.Now;
string x;
if(dt.HasValue)
x = dt.Value.ToString("dd/MM/yyyy");
Upvotes: 2
Reputation: 354774
Because Nullable<T>
is implemented in C# in a way that makes instances of that struct appear as nullable types. When you have DateTime?
it's actually Nullable<DateTime>
, when you assign null
to that, you're setting HasValue
to false
behind the scenes, when you check for null
, you're checking for HasValue
, etc. The ?.
operator is just implemented in a way that it replaces the very same idioms that work for reference types also for nullable structs. Just like the rest of the language makes nullable structs similar to reference types (with regard to null
-ness).
Upvotes: 20