Я пытаюсь использовать условный оператор, но я становлюсь одержимым типом, он думает, что результат должен быть.
Ниже пример, что я умудрился показывать проблему, которую я имею:
class Program
{
public static void OutputDateTime(DateTime? datetime)
{
Console.WriteLine(datetime);
}
public static bool IsDateTimeHappy(DateTime datetime)
{
if (DateTime.Compare(datetime, DateTime.Parse("1/1")) == 0)
return true;
return false;
}
static void Main(string[] args)
{
DateTime myDateTime = DateTime.Now;
OutputDateTime(IsDateTimeHappy(myDateTime) ? null : myDateTime);
Console.ReadLine(); ^
} |
} |
// This line has the compile issue ---------------+
На строке, обозначенной выше, я получаю следующую ошибку компиляции:
Тип условного выражения не может быть определен, потому что нет никакого неявного преобразования между' <пустой>' и 'Системой. DateTime'
Я смущен, потому что параметр является nullable типом (DateTime?). Почему это должно преобразовать вообще? Если это является пустым, затем используют это, если это - время даты, затем используют это.
У меня создалось впечатление что:
condition ? first_expression : second_expression;
совпал с:
if (condition)
first_expression;
else
second_expression;
Очевидно дело обстоит не так. Каково обоснование позади этого?
(ПРИМЕЧАНИЕ: Я знаю, что, если я делаю "myDateTime" nullable DateTime затем, он будет работать. Но почему этому нужен он?
Как я заявил ранее, это - изобретенный пример. В моем реальном примере "myDateTime" является отображенным значением данных, которое не может быть сделано nullable.)
Компилятор выводит тип результата условного оператора не из использования результата, а из типов его аргументов. Компилятор не работает, когда видит это выражение, потому что он не может определить тип результата:
IsDateTimeHappy(myDateTime) ? null : myDateTime;
Поскольку null
и DateTime
несовместимы, вам необходимо сообщить компилятору, какой тип должно быть. Приведение должно помочь:
DateTime? x = IsDateTimeHappy(myDateTime) ? (DateTime?)null : myDateTime;
OutputDateTime(x);
Теперь у компилятора не будет проблем. Вы также можете написать вышеупомянутое в одной строке, если хотите (но я, вероятно, не стал бы этого делать):
OutputDateTime(IsDateTimeHappy(myDateTime) ? (DateTime?)null : myDateTime);
Эрик Липперт имеет хороший ответ , который также актуален здесь и более подробно описывает, как компилятор определяет типы.
Причина в том, что тернарный оператор ожидает, что оба операнда будут одного типа. Весь оператор отрабатывается ДО того, как он присваивается результату (в данном случае передается в функцию), поэтому компилятор не может знать, каков тип результата.
IsDateTimeHappy(myDateTime) ? null : myDateTime
В приведенном выше случае нет пути преобразования между null
и DateTime
. Как только вы приведете один из них к DateTime?
, компилятор сможет преобразовать другой:
IsDateTimeHappy(myDateTime) ? (DateTime?)null : myDateTime
//OR
IsDateTimeHappy(myDateTime) ? null : (DateTime?)myDateTime
Первая строка кода выше работает, потому что компилятор может преобразовать DateTime
в DateTime?
через неявный оператор преобразования:
//In Nullable<T>
public static implicit operator T?(T value);
Вторая строка работает, потому что null
может быть присвоен DateTime?
, поскольку последний является ссылочным типом.
Неявное преобразование не разрешено оператором return. Если бы у вас было
if (condition)
return first_expression;
else
return second_expression;
, вы бы сравнивали яблоки с яблоками. И у вас не будет проблем - как вы заявили.
В вашем случае у вас выделено так много места в стеке для DateTime - типа значения, не допускающего значения NULL. Итак, вы делаете заявление, которое не имеет никакого смысла для компилятора. Если вы скажете, что я дам вам A
или B
, то A
и B
должны быть тоже самое. В вашем случае B
никогда не может быть A
.
Думаю, здесь тоже есть ответ: Обнуляемые типы и тернарный оператор: почему `? 10: null` запрещено?
Надеюсь, это то, что вам нужно. =]
Компилятор сообщает следующее:
Если
IsDateTimeHappy (myDateTime)
равноfalse
, то мне нужно вернуть значение типаDateTime
, равное наmyDateTime
. Если этоистина
, то мне нужно вернуть значение, равноеnull
, но вы не сказали мне, какой это должен быть тип!
Вот почему ответ Марка - это решение. После того, как вы предоставите приведение, сообщающее компилятору, какой тип значения будет возвращен, если условие равно истина
, он может проверить, могут ли возвращаемые значения истина
и ложь
быть преобразованы в (или имеют) один и тот же тип.
Ура, Марк! ; -)
Вместо null
используйте default (DateTime?)
, и тогда обе стороны тернарного элемента будут иметь совместимые типы.