2013-05-22 11 views
13

Dopo aver visto come double.Nan == double.NaN è sempre falso in C#, sono diventato curioso di sapere come l'uguaglianza è stata implementata sotto il cofano. Così ho usato ReSharper per decompilare il doppio struct, ed ecco cosa ho trovato:Quando è un System.Double non un doppio?

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

    public const double NaN = double.NaN; 

    // more stuff removed... 
} 

Questo sembra indicare la struct Double dichiara una costante che viene definita in termini di questo speciale minuscole double, anche se' Ho sempre pensato che i due fossero completamente sinonimi. Per di più, se vado all'implementazione sul doppio minuscolo, Resharper semplicemente scorre me alla dichiarazione nella parte superiore del file. Allo stesso modo, passare all'implementazione di NaN in minuscolo mi porta alla dichiarazione costante nella riga precedente!

Quindi sto cercando di capire questa definizione apparentemente ricorsiva. Questo è solo un artefatto del decompilatore? Forse una limitazione in Resharper? Oppure questo doppio minuscolo in realtà è una bestia completamente diversa - rappresenta qualcosa di più basso dal CLR/CTS?

Da dove proviene veramente lo NaN?

+2

È correlato? http://stackoverflow.com/questions/4751885/how-are-the-primitive-types-defined-non-recursively E anche http://stackoverflow.com/questions/16113850/if-int32-is-just-an -alias-per-int-how-can-the-int32-class-use-an-int –

+3

Basta usare VS per visualizzare i metadati mostra 'public const double NaN = 0.0/0.0;' –

+1

'NaN' significa' Not a Number' e può essere positivo o negativo, proprio come 'Infinity'. Nel caso qualcuno si stia chiedendo. – Nolonar

risposta

8

Di gran lunga la migliore fonte che è possibile ottenere per gli assembly .NET è il codice sorgente effettivo utilizzato per crearli. Beats qualsiasi decompilatore per la precisione, i commenti possono essere abbastanza utili pure. Scarica il Reference Source.

Si vedrà anche che Double.NaN non è definito in IL come presuppone Marc, si trova in un file di codice sorgente C#.Il file di codice sorgente di net/clr/bcl/system/double.cs mostra la dichiarazione vera:

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

che sfrutta il compilatore C# valutare espressioni costanti in fase di compilazione. O per dirla in modo ironico, NaN è definito dal compilatore C++ poiché questo è il linguaggio utilizzato per scrivere il compilatore C#;)

15

Attenzione a codice decompilato, soprattutto se è per qualcosa di integrato. La IL effettivo qui (per NET 4.5, almeno) è:

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

cioè questo viene gestito direttamente in IL tramite NaN token.

Tuttavia, poiché è un const (literal in IL), verrà "bruciato" nel sito di chiamata; in qualsiasi altro luogo che utilizza double.NaN utilizza float64(NaN). Allo stesso modo, ad esempio, se faccio:

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

entrambe queste assegnazioni cercherà identica in finale IL (che saranno entrambi ldc.i4.2).

Per questo motivo, la maggior parte dei decompilatori riconoscerà il modello IL NaN e lo rappresenta con l'equivalente della lingua di double.NaN. Ma ciò non significa che il codice sia esso stesso ricorsivo; probabilmente non hanno un assegno per "ma è doppio.NaN stesso?". In definitiva, questo è semplicemente un caso speciale, in cui float64(NaN) è un valore riconosciuto in IL.

Incidentalmente, riflettore decompila come:

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

Anche questo non significa che questa è la verità: p Semplicemente che questo è qualcosa che può avere lo stesso risultato finale.

Problemi correlati