Есть ли "?". оператор делает что-нибудь еще, кроме проверки на нуль?
Как вы знаете, DateTime?
не имеет параметризованного ToString
(для форматирования вывода) и делает что-то вроде
DateTime? dt = DateTime.Now;
string x;
if(dt != null)
x = dt.ToString("dd/MM/yyyy");
будет бросать
Нет перегрузки для метода 'ToString' принимает 1 аргумент
Но, поскольку С# 6.0 и оператор Elvis (?.
), вышеуказанный код можно заменить на
x = dt?.ToString("dd/MM/yyyy");
который... работает! Почему?
Ответы
Ответ 1
Поскольку Nullable<T>
реализуется на С# таким образом, что экземпляры этой структуры отображаются как типы с нулевым значением. Если у вас есть DateTime?
на самом деле Nullable<DateTime>
, когда вы назначаете null
этому, вы устанавливаете HasValue
на false
за кулисами, когда вы проверяете null
, вы проверяете на HasValue
и т.д. Оператор ?.
просто реализуется таким образом, что он заменяет те же самые идиомы, которые работают для ссылочных типов также для нулевых структур. Точно так же, как и весь остальной язык, он делает структуры с нулевыми значениями похожими на ссылочные типы (в отношении null
-ness).
Ответ 2
Короткий ответ:
DateTime?
- это только сладкий синтаксис Nullable<DateTime>
, который не содержит свойств и методов DateTime
, а Оператор Элвиса работает с не-Nullable Nullable<DateTime>.Value
.
Объяснение:
Следующий код:
DateTime? dt = DateTime.Now;
string x;
if (dt != null)
x = dt?.ToString("dd/MM/yyyy");
При декомпиляции как C# 5.0
получается следующий результат:
DateTime? nullable = new DateTime?(DateTime.Now);
if (nullable.HasValue)
{
string str = nullable.HasValue ? nullable.GetValueOrDefault().ToString("dd/MM/yyyy") : null;
}
Боковое примечание: string
кажется объявленным внутри if
не имеет значения из-за подъема на уровне MSIL
, и поскольку значение не используется позже, декомпилятор показывает это, как если бы он был объявлен внутри области if
.
Как вы видите, и поскольку DateTime?
является только сладким синтаксисом для Nullable<DateTime>
, C#
имеет конкретную ссылку для Nullable<T>
с оператором Элвиса, что делает его возвращаемое значение непустым значением T сам.
Результат целого Elvis operator
должен быть Nullable
, поэтому, если вы хотите получить значение не string
, оно должно быть либо Nullable<T>
, либо ReferenceType
> но это не меняет того факта, что если оператору удалось получить значение Nullable<DateTime>
- возвращенный DateTime
больше не Nullable<DateTime>
.
Ответ 3
Учитывая:
DateTime? dt = DateTime.Now;
string x;
if(dt != null)
x = dt.ToString("dd/MM/yyyy");
Здесь dt
есть DateTime?
или Nullable<DateTime>
ведьма не IFormatable
и не имеет метода ToString(string format)
.
Так что он бросает.
Теперь рассмотрим:
x = dt?.ToString("dd/MM/yyyy");
?.
является синтаксическим сахаром для:
dt.HasValue ? dt.Value.ToString("dd/MM/yyyy"): null
Здесь dt.Value
есть DateTime
witch is IFormatable
и имеет метод ToString(string format)
.
Наконец, хороший способ написать первый код в С# 5.0:
DateTime? dt = DateTime.Now;
string x;
if(dt.HasValue)
x = dt.Value.ToString("dd/MM/yyyy");