Głównym problemem jest to, że zakładasz, że wszystkie biblioteki .NET (w tym przypadku Extended Numerics Library, która nie jest częścią BCL) są napisane w standardowym języku C #. Nie zawsze tak jest, a różne języki mają różne zasady.
W standardowym języku C # fragment kodu, który widzisz, spowodowałby przepełnienie stosu ze względu na sposób działania rozpoznawania przeciążenia operatora. Jednak kod nie jest w rzeczywistości w standardowym języku C # - w zasadzie wykorzystuje nieudokumentowane funkcje kompilatora C #. Zamiast dzwonić do operatora, emituje następujący kod:
ldarg.0
ldarg.1
ceq
ret
To wszystko :) Nie ma 100% odpowiednika kodu C # - to po prostu nie jest możliwe w C # z własnym typem.
Nawet wtedy rzeczywisty operator nie jest używany podczas kompilowania kodu C # - kompilator wykonuje kilka optymalizacji, jak w tym przypadku, gdzie zastępuje op_Equality
wywołanie prostym ceq
. Ponownie, nie możesz tego powtórzyć we własnej DoubleEx
strukturze - to magia kompilatora.
Z pewnością nie jest to wyjątkowa sytuacja w .NET - jest mnóstwo nieprawidłowego kodu, standardowy C #. Powody są zwykle (a) hacki kompilatora i (b) inny język, z dziwnymi (c) hackami środowiska uruchomieniowego (patrzę na ciebie Nullable
!).
Ponieważ kompilator Roslyn C # jest źródłem oepn, mogę wskazać miejsce, w którym zdecydowano o rozwiązaniu problemu:
Miejsce, w którym wszystkie operatory binarne są rozwiązywane
„Skróty” dla operatorów wewnętrznych
Kiedy spojrzysz na skróty, zobaczysz, że równość między double i double skutkuje wewnętrznym operatorem double, nigdy faktycznym ==
operatorem zdefiniowanym w typie. System typów .NET musi udawać, że Double
jest typem jak każdy inny, ale C # tego nie robi - double
jest prymitywem w C #.