La principale confusione qui è che stai assumendo che tutte le librerie .NET (in questo caso, la Libreria numerica estesa, che non fa parte del BCL) siano scritte in C # standard. Questo non è sempre il caso e lingue diverse hanno regole diverse.
In C # standard, il pezzo di codice che si vede comporterebbe un overflow dello stack, a causa del modo in cui funziona la risoluzione di sovraccarico dell'operatore. Tuttavia, il codice non è in realtà in C # standard - utilizza fondamentalmente funzionalità non documentate del compilatore C #. Invece di chiamare l'operatore, emette questo codice:
ldarg.0
ldarg.1
ceq
ret
Questo è tutto :) Non esiste un codice C # equivalente al 100% - questo semplicemente non è possibile in C # con il tuo tipo.
Anche in questo caso, l'operatore effettivo non viene utilizzato durante la compilazione del codice C #: il compilatore esegue una serie di ottimizzazioni, come in questo caso, in cui sostituisce la op_Equality
chiamata con il semplice ceq
. Ancora una volta, non puoi replicarlo nella tua DoubleEx
struttura: è la magia del compilatore.
Questa non è certamente una situazione unica in .NET - c'è un sacco di codice che non è valido, C # standard. I motivi sono di solito (a) hack del compilatore e (b) un linguaggio diverso, con gli hack dispari (c) di runtime (ti sto guardando Nullable
!!).
Poiché il compilatore Roslyn C # è oepn source, posso effettivamente indicarti il punto in cui viene decisa la risoluzione del sovraccarico:
Il luogo in cui vengono risolti tutti gli operatori binari
Le "scorciatoie" per operatori intrinseci
Quando guardi le scorciatoie, vedrai che l'uguaglianza tra doppio e doppio risulta nell'operatore intrinseco doppio, mai nell'operatore effettivo ==
definito sul tipo. Il sistema di tipi .NET deve fingere che Double
sia un tipo come un altro, ma C # no - double
è una primitiva in C #.