Все началось с трюка, который кто-то мне задал.. (Он упоминается в книге - С# в двух словах) Вот суть этого.
Double a = Double.NaN;
Console.WriteLine(a == a); // => false
Console.WriteLine(a.Equals(a)); // => true
Вышеприведенное не кажется правильным. a всегда должен быть == для себя (ссылочное равенство), и оба должны быть согласованными.
Кажется, что Double перегружает оператор ==. Подтверждено рефлектором следующим образом:
[__DynamicallyInvokable]
public static bool operator ==(double left, double right)
{
    return (left == right);
}
Странный, который выглядит рекурсивным и не упоминает специфическое поведение NaN. Так почему он возвращает false?
Итак, я добавляю еще несколько кода, чтобы отличить
var x = "abc";
var y = "xyz";
Console.WriteLine(x == y); // => false
Теперь я вижу
    L_0001: ldc.r8 NaN
    L_000a: stloc.0 
    L_000b: ldloc.0 
    L_000c: ldloc.0 
    L_000d: ceq 
    L_000f: call void [mscorlib]System.Console::WriteLine(bool)
    L_0014: nop 
    L_0015: ldloca.s a
    L_0017: ldloc.0 
    L_0018: call instance bool [mscorlib]System.Double::Equals(float64)
    L_001d: call void [mscorlib]System.Console::WriteLine(bool)
    L_0022: nop 
    L_0023: ldstr "abc"
    L_0028: stloc.1 
    L_0029: ldstr "xyz"
    L_002e: stloc.2 
    L_002f: ldloc.1 
    L_0030: ldloc.2 
    L_0031: call bool [mscorlib]System.String::op_Equality(string, string)
    L_0036: call void [mscorlib]System.Console::WriteLine(bool)
-  для удвоений, вызов оператора == преобразуется в код ceqIL
- где как для строк, он переводится в System.String:: op_Equality (строка, строка).
Разумеется, документация для ceq указывает, что она предназначена для чисел с плавающей запятой и NaN. Этим объясняются наблюдения.
Вопросы:
- Почему op_Equality определен в Double? (И реализация не влияет на специфическое поведение NaN)
- Когда он вызывается?
