Проблема з незмінним типом?: Умовний оператор


154

Може хтось пояснить, чому це працює в C # .NET 2.0:

    Nullable<DateTime> foo;
    if (true)
        foo = null;
    else
        foo = new DateTime(0);

... але це не так:

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

Остання форма дає мені помилку компіляції: "Тип умовного вираження неможливо визначити, оскільки немає неявного перетворення між" <null> "та" System.DateTime "."

Не те, що я не можу використовувати перший, але другий стиль більше відповідає решті мого коду.


12
Ви можете зекономити багато набравши, використовуючи DateTime? замість Nullable <DateTime>.
Стюарт Джонсон

Відповіді:


325

Це питання вже задавали ще чимало разів. Компілятор каже вам, що він не знає, як перетворити nullв DateTime.

Рішення просте:

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

Зауважте, що це Nullable<DateTime>може бути написано, DateTime?що заощадить купу введення тексту.


Працює досить добре, але тепер ви не можете скасувати нуль foo - це завжди матиме значення. Навпаки, цього немає - як каже MojoFilter "Це тому, що в потрійному операторі два значення повинні бути одного типу".
DilbertDave

@DilbertDave Інформація з допису MojoFilter невірна.
Мішакс

4
Додам, що компілятор намагається відгадати результат, що випливає з потрійної операції, не дивлячись на змінну, якій вона призначена, а дивлячись замість операндів. Він знаходить, <null>і DateTimeзамість того, щоб знайти загальний тип предків, він просто намагається знайти перетворення між собою. (Додатковий біт: C # розпізнає <null>тип, тобто тип кожного nullвиразу.)
IllidanS4 хоче, щоб Моніка повернулася

Якщо його вже задавали ще чимало разів, де прапор дублюючого питання?
starmandeluxe

@starmandeluxe всі вони, ймовірно, вказують тут (принаймні, на те, як я потрапив сюди)
Скотт Чемберлен

19

FYI (Offtopic, але вишуканий і пов'язаний із змінними типами) у нас є зручний оператор лише для змінних типів, які називаються оператором null coalescing

??

Використовується так:

// Left hand is the nullable type, righthand is default if the type is null.
Nullable<DateTime> foo;
DateTime value = foo ?? new DateTime(0);

9
Як це відповідає на його запитання ??
Стюарт Джонсон

3
Нік намагається призначити нуль foo, якщо якась умова є правдою. Null coalesce призначить DateTime (0) значенням, якщо foo є null. Два цілком не пов'язані між собою.
Джеромі Ірвін

4
Звідси FYI, офтопік, але приємна річ, яку потрібно знати.
FlySwat

Ну гаразд. Це досить корисно знати.
Джеромі Ірвін

8

Це тому, що в потрійному операторі два значення повинні відповідати одному типу.


10
Ні, вони не повинні бути одного типу. Або другий операнд повинен бути неявно конвертованим у тип третього операнда, або навпаки.
Мішакс

3

Мені відомо, що це запитання було задано в 2008 році, і це вже через 5 років, але відповідь, позначена як відповідь, мене не влаштовує. Справжня відповідь полягає в тому, що DateTime - це структура, і як структура вона не сумісна з null. Ви маєте два способи вирішити це:

По-перше, це зробити null сумісним з DateTime (наприклад, призначати null DateTime?, Як пропонує пан з 70 оновленнями, або призначати null до Object або ValueType).

Друга полягає в тому, щоб зробити DateTime сумісним з null (наприклад, передати DateTime в DateTime?).


3

Іншим рішенням, подібним до прийнятого, є використання defaultключового слова C # . Незважаючи на те, що визначено за допомогою дженерики, він фактично застосовний до будь-якого типу.

Приклад використання, застосованого до питання ОП:

Nullable<DateTime> foo;
foo = true ? default(DateTime) : new DateTime(0);

Приклад використання з поточно прийнятою відповіддю:

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

Також, використовуючи default, вам не потрібно вказувати змінну як nullableдля того, щоб призначити їй nullзначення. Компілятор автоматично призначить значення за замовчуванням конкретного типу змінної, і помилка не буде виникати. Приклад:

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

13
Неправда, default(DateTime)не нуль, це " 1.1.0001 0:00:00", те саме, що new DateTime(0).
IllidanS4 хоче, щоб Моніка повернулася

@ IllidanS4, я не казав, що це дорівнює null, лише те, що, використовуючи default()його, можна призначити його nullableзначення (як MSDN). Приклади я показую продемонструвати універсальність , що він може бути використаний з Nullable<DateTime>, DateTime?і просто DateTime. Якщо ви вважаєте, що це неправильно, чи можете ви надати PoC, де вони не спрацьовують?
newf Furniturey

3
Що ж, запитувач хотів зберігати nullзмінну, ні default(DateTime), тож це в кращому випадку вводить в оману. Це не «універсальний» , як ви маєте на увазі, так як вираз в цілому має все той же тип - DateTimeі ви можете замінити default(DateTime)з , new DateTime()і він буде робити те ж саме. Можливо, default(DateTime?)це ви мали на увазі, оскільки це насправді дорівнює null.
IllidanS4 хоче, щоб Моніка повернулася
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.