2013-05-22 34 views
13

看到在C#中double.Nan == double.NaN總是錯誤的,我很好奇平等是如何實現的。所以我用ReSharper的反編譯的雙重結構,這裏是我發現:什麼時候是一個System.Double不是雙?

public struct Double : IComparable, IFormattable, IConvertible, IComparable<double>, IEquatable<double> 
{ 
    // stuff removed... 

    public const double NaN = double.NaN; 

    // more stuff removed... 
} 

這似乎預示着該結構Double聲明是在這個特殊的小寫double形式定義的常量,但我」 d總是認爲這兩者完全是同義詞。更重要的是,如果我使用小寫雙精度實現,Resharper只需將我滾動到文件頂部的聲明即可。同樣,跳轉到執行小寫的NaN只需要我在行中的前一個常量聲明!

所以我想了解這個看似遞歸的定義。這只是反編譯器的人造物嗎?也許Resharper的限制?或者,這個小寫字母雙重實際上是一個完全不同的野獸 - 代表CLR/CTS的更低層次的東西?

NaN究竟是從哪裏來的?

+2

這與此相關嗎? http://stackoverflow.com/questions/4751885/how-are-the-primitive-types-defined-non-recursively而且還http://stackoverflow.com/questions/16113850/if-int32-is-just-an -alias-for-int-how-can-the-int32-class-use-an-int –

+3

只用VS查看元數據顯示'public const double NaN = 0.0/0.0;' –

+1

'NaN'表示'不是數字「,並且可以是正數或負數,就像」無限「一樣。如果有人想知道。 – Nolonar

回答

8

到目前爲止,您可以獲得.NET程序集的最佳源代碼是用於構建它們的實際源代碼。擊敗任何反編譯器的準確性,評論也可以相當有用。下載Reference Source

然後,您會看到Double.NaN未在IL中定義,因爲Marc假定它實際上是在C#源代碼文件中。該net/clr/bcl/system/double.cs源代碼文件顯示真正聲明:

public const double NaN = (double)0.0/(double)0.0; 

這需要C#編譯器在編譯時評估常量表達式的優勢。或者把它放在嘴邊,NaN由C++編譯器定義,因爲這是用來編寫C#編譯器的語言;)

15

當心看反編譯的代碼,特別是如果它是內置的東西。這裏的實際IL(用於.NET 4.5,至少)是:

.field public static literal float64 NaN = float64(NaN) 
{ 
    .custom instance void __DynamicallyInvokableAttribute::.ctor() 
} 

即這是直接在IL經由NaN令牌處理。

但是,因爲它是constliteral in IL),它將被「燒入」呼叫站點;其他地方使用double.NaN使用float64(NaN)。類似地,例如,如果我做:

const int I = 2; 
int i = I; 
int j = 2; 

這些分配的兩者看起來相同在最終IL(他們都將是ldc.i4.2)。

因此,大多數反編譯器都會識別IL模式NaN並用語言等效的double.NaN來表示它。但這並不意味着代碼本身是遞歸的;他們可能只是沒有檢查「但它是雙重的.NaN本身?」。最終,這只是一個特殊情況,其中float64(NaN)是IL中的公認值。

順便說一句,反編譯反射它:

[__DynamicallyInvokable] 
public const double NaN = (double) 1.0/(double) 0.0; 

這一次不意味着這是真理:P僅僅這一點是可以具有相同的最終結果。

相關問題