La principal confusión aquí es que está asumiendo que todas las bibliotecas .NET (en este caso, la Biblioteca de Numéricos Extendida, que no es parte del BCL) están escritas en C # estándar. Este no es siempre el caso, y diferentes idiomas tienen diferentes reglas.
En C # estándar, el fragmento de código que está viendo provocaría un desbordamiento de la pila, debido a la forma en que funciona la resolución de sobrecarga del operador. Sin embargo, el código no está realmente en C # estándar, básicamente usa características no documentadas del compilador de C #. En lugar de llamar al operador, emite este código:
ldarg.0
ldarg.1
ceq
ret
Eso es todo :) No hay un código C # 100% equivalente, esto simplemente no es posible en C # con su propio tipo.
Incluso entonces, el operador real no se usa al compilar código C #: el compilador realiza un montón de optimizaciones, como en este caso, donde reemplaza la op_Equality
llamada con solo lo simple ceq
. Una vez más, no puede replicar esto en su propia DoubleEx
estructura: es la magia del compilador.
Ciertamente, esta no es una situación única en .NET: hay mucho código que no es válido, estándar C #. Las razones son generalmente (a) hacks de compilación y (b) un lenguaje diferente, con los hacks de tiempo de ejecución (c) extraños (¡te estoy mirando Nullable
!).
Dado que el compilador Roslyn C # es una fuente abierta, puedo señalarle el lugar donde se decide la resolución de sobrecarga:
El lugar donde se resuelven todos los operadores binarios.
Los "atajos" para operadores intrínsecos
Cuando observe los accesos directos, verá que la igualdad entre doble y doble da como resultado el operador doble intrínseco, nunca en el ==
operador real definido en el tipo. El sistema de tipos .NET tiene que fingir que Double
es un tipo como cualquier otro, pero C # no, double
es una primitiva en C #.