A principal confusão aqui é que você está assumindo que todas as bibliotecas .NET (neste caso, a Biblioteca Numérica Estendida, que não faz parte da BCL) são gravadas em C # padrão. Isso nem sempre é o caso, e diferentes idiomas têm regras diferentes.
No C # padrão, o trecho de código que você vê resultaria em um estouro de pilha, devido à maneira como a resolução de sobrecarga do operador funciona. No entanto, o código não está realmente no C # padrão - ele basicamente usa recursos não documentados do compilador C #. Em vez de chamar o operador, ele emite este código:
ldarg.0
ldarg.1
ceq
ret
É isso :) Não há código C # 100% equivalente - isso simplesmente não é possível em C # com seu próprio tipo.
Mesmo assim, o operador real não é usado ao compilar o código C # - o compilador faz várias otimizações, como neste caso, onde substitui a op_Equality
chamada pelo simples ceq
. Novamente, você não pode replicar isso em sua própria DoubleEx
estrutura - é mágica do compilador.
Certamente, essa não é uma situação única no .NET - há muito código que não é válido, C # padrão. Os motivos são geralmente (a) hacks de compilador e (b) um idioma diferente, com os hacks de tempo de execução ímpares (c) (estou olhando para você Nullable
!).
Como o compilador C # da Roslyn é uma fonte oepn, posso apontar o local onde a resolução de sobrecarga é decidida:
O local em que todos os operadores binários são resolvidos
Os "atalhos" para operadores intrínsecos
Ao olhar para os atalhos, você verá que a igualdade entre duplo e duplo resulta no operador duplo intrínseco, nunca no ==
operador real definido no tipo. O sistema de tipos .NET precisa fingir que Double
é um tipo como outro qualquer, mas o C # não - double
é um primitivo no C #.