2015-07-30 4 views
2

Такое поведение звучит неправильно для меня.Nullable <= vs == результат сравнения

DateTime? birth = null; 
DateTime? death = null; 

Console.WriteLine(birth == death); // true 
Console.WriteLine(birth <= death); // false 

Почему это так? Это невероятно странно. Конечно, я имею в виду, почему второе выражение не оценивает значение true.

EDIT:

Я понимаю, что следующие сравнения возвращают false, потому что он не может сказать, как они соотносятся друг с другом:

Console.WriteLine(birth < death); // false 
Console.WriteLine(birth > death); // false 

Это вполне понятно поведение. Но ... посмотрим на логику:

  • <= означает < или ==
  • мы не знаем, как читать < - это может быть true или false
  • мы знаем, что == является true
  • , поскольку одно из условий: true, другое состояние не может не соответствует результат. Это логика или, а не и.

Я считаю, что true or something else должно быть правдой.

Я знаю, что команда C# создала его таким образом, но моя интуиция отличается. Так как умные люди написали C# с такими правилами, я просто хочу узнать почему моя интуиция здесь не так :)

+0

Вы спрашиваете, почему язык разработан таким образом, или хотите доказать, что поведение, которое вы видите, соответствует языку? –

+0

@JonSkeet Почему язык спроектирован таким образом :) Я просто не понимаю причины, чтобы заставить его вести себя таким образом ... –

+0

false в этом случае означает «неизвестно». Дизайнеры могли бы реализовать операторы сравнения (исключая == и! =), Чтобы они возвращали нулевый логический результат, а не логический, но читаемость кода, использующего их, была бы явно затронута. Я предполагаю, что они предпочли реализовать его таким образом, хотя могут быть угловые случаи, которые четко документированы. –

ответ

1

Я понимаю, что вы не ищете спецификации, а объясните, почему именно nullables были разработаны таким образом.

Чтобы устранить неоднозначность, разработчики могли бы позволить этим операторам вернуть значение bool? вместо значения bool, которое было бы нулевым, если один из операндов равен NULL.

Но если бы они сделали этот выбор, код будет выглядеть следующим образом:

bool? comparison = birth <= death; 
if (comparison.HasValue && comparison.Value) 
{ 
} 

который немного громоздко.

Как примечание стороны, кажется, что, глядя на И.Л., компилятор С # генерирует сравнение со значениями по умолчанию, а затем проверяет, если один из операндов является нулем, которая кажется немного странным ...

.method private hidebysig static void Main(string[] args) cil managed 
{ 
    .locals init ([0] valuetype [mscorlib]System.Nullable`1<int32> x, 
      [1] valuetype [mscorlib]System.Nullable`1<int32> V_1, 
      [2] valuetype [mscorlib]System.Nullable`1<int32> V_2) 
    IL_0000: ldloca.s x 
    IL_0002: ldc.i4.1 
    IL_0003: call  instance void valuetype [mscorlib]System.Nullable`1<int32>::.ctor(!0) 
    IL_0008: ldc.i4.2 
    IL_0009: newobj  instance void valuetype [mscorlib]System.Nullable`1<int32>::.ctor(!0) 
    IL_000e: ldloc.0 
    IL_000f: stloc.1 
    IL_0010: stloc.2 
    IL_0011: ldloca.s V_1 
    IL_0013: call  instance !0 valuetype [mscorlib]System.Nullable`1<int32>::GetValueOrDefault() 
    IL_0018: ldloca.s V_2 
    IL_001a: call  instance !0 valuetype [mscorlib]System.Nullable`1<int32>::GetValueOrDefault() 
    IL_001f: ble.s  IL_0024 
    IL_0021: ldc.i4.0 
    IL_0022: br.s  IL_0033 
    IL_0024: ldloca.s V_1 
    IL_0026: call  instance bool valuetype [mscorlib]System.Nullable`1<int32>::get_HasValue() 
    IL_002b: ldloca.s V_2 
    IL_002d: call  instance bool valuetype [mscorlib]System.Nullable`1<int32>::get_HasValue() 
    IL_0032: and 
    IL_0033: brfalse.s IL_003a 
    IL_0035: call  void [mscorlib]System.Console::WriteLine() 
    IL_003a: ret 
} // end of method Program::Main 

Это также репликация логики, уже присутствующей в статическом классе Nullable.

4

Согласно ECMA-334 стандарта (8,19 Nullable типов) (курсив мой):

оператор сравнения (==, !=, <, >, <=, >=) имеет поднятую форму, когда типы операндов оба не-обнуляемые типов значений и тип результат bool. Поднятая форма оператора сравнения формируется путем добавления модификатора ? к каждому типу операнда (но не к типу результата). Поднятые формы операторов == и != считают два нулевых значения равными, а значение null равно не равному ненулевому значению. Поднятые формы <, >, <= и >= Операторы return false, если один или оба операнда пустые.