Aus irgendeinem Grund schlich ich mich in die .NET Framework-Quelle für die Klasse Double
und fand heraus, dass die Deklaration von ==
lautet:
Dieselbe Logik gilt für jeder -Operator.
In Wirklichkeit verwandelt der Compiler den Operator ==
in einen ceq
IL-Code, und der von Ihnen erwähnte Operator wird nicht aufgerufen.
Der Grund für den Operator im Quellcode ist wahrscheinlich, dass er von anderen Sprachen als C # aufgerufen werden kann, die ihn nicht direkt in einen CEQ
-Aufruf (oder durch Reflektion) übersetzen. Der Code innerhalb des Operators wird in CEQ
kompiliert, so dass es keine unendliche Rekursion gibt.
Wenn Sie den Operator über die Reflektion aufrufen, können Sie tatsächlich sehen, dass der Operator aufgerufen wird (und nicht eine CEQ
-Anweisung) und offensichtlich nicht unendlich rekursiv ist (da das Programm wie erwartet beendet wird):
Resultierende IL (zusammengestellt von LinqPad 4):
%Vor% Interessanterweise existieren die gleichen Operatoren NICHT (entweder in der Referenzquelle oder über Reflektion) für ganzzahlige Typen, nur Single
, Double
, Decimal
, String
und DateTime
, was meine widerlegt Theorie, dass sie existieren, um aus anderen Sprachen aufgerufen zu werden. Offensichtlich können Sie zwei Ganzzahlen in anderen Sprachen ohne diese Operatoren gleichsetzen, also kommen wir zurück auf die Frage "Warum existieren sie für double
"?
Die Hauptverwirrung hier ist, dass Sie davon ausgehen, dass alle .NET-Bibliotheken (in diesem Fall die Extended Numerics Library, die nicht ein Teil der BCL ist) in Standard-C # geschrieben werden. Dies ist nicht immer der Fall und verschiedene Sprachen haben unterschiedliche Regeln.
In Standard-C # führt der Code, den Sie sehen, zu einem Stapelüberlauf, da die Überladungsauflösung des Operators funktioniert. Allerdings ist der Code nicht wirklich in Standard-C # - es verwendet im Grunde undokumentierte Funktionen des C # -Compilers. Anstatt den Operator aufzurufen, gibt er diesen Code aus:
%Vor%Das ist es :) Es gibt keinen 100% äquivalenten C # -Code - das ist einfach nicht in C # mit eigenem -Typ möglich.
Selbst dann wird der eigentliche Operator nicht verwendet, wenn der C # -Code kompiliert wird - der Compiler führt eine Reihe von Optimierungen durch, wie in diesem Fall, wo er den op_Equality
-Aufruf nur durch den einfachen ceq
ersetzt. Auch dies kann nicht in Ihrer eigenen DoubleEx
struct repliziert werden - es ist die Compiler-Magie.
Dies ist sicherlich keine einzigartige Situation in .NET - es gibt viel Code, der nicht gültig ist, Standard-C #. Die Gründe sind normalerweise (a) Compiler-Hacks und (b) eine andere Sprache, mit den ungeraden (c) Laufzeit-Hacks (Ich schaue dich an, Nullable
!).
Da der Roslyn C # -Compiler eine OEPN-Quelle ist, kann ich Sie auf den Ort verweisen, an dem die Überladungsauflösung entschieden wird:
Der Ort, an dem sich alle binären Operatoren befinden aufgelöst
Die "Abkürzungen" für intrinsische Operatoren
Wenn Sie sich die Verknüpfungen ansehen, sehen Sie, dass die Gleichheit zwischen double und double im intrinsischen Doppeloperator never im tatsächlichen Operator ==
, der für den Typ definiert ist, resultiert. Das .NET-Typsystem muss so aussehen, als wäre Double
ein Typ wie jeder andere, aber C # nicht - double
ist ein Primitiv in C #.
Die Quelle der primitiven Typen kann verwirrend sein. Hast du die erste Zeile von Double
struct gesehen?
Normalerweise können Sie keine rekursive Struktur wie folgt definieren:
%Vor% Primitive Typen haben auch ihre ursprüngliche Unterstützung in CIL. Normalerweise werden sie nicht wie objektorientierte Typen behandelt. Ein Double ist nur ein 64-Bit-Wert, wenn es in CIL als float64
verwendet wird. Wenn es jedoch als normaler .NET-Typ behandelt wird, enthält es einen tatsächlichen Wert und es enthält Methoden wie alle anderen Typen.
Was Sie hier sehen, ist also die gleiche Situation für Betreiber. Normalerweise, wenn Sie den Typ doppelter Typ direkt verwenden, wird es nie aufgerufen. BTW, seine Quelle sieht in CIL so aus:
%Vor% Wie Sie sehen, gibt es keine Endlosschleife (das ceq
Gerät wird verwendet, anstatt das System.Double::op_Equality
aufzurufen). Wenn also ein double wie ein Objekt behandelt wird, wird die operator-Methode aufgerufen, die sie schließlich als primitiven Typ float64
auf CIL-Ebene behandelt.
Ich habe mir die CIL mit JustDecompile angeschaut. Der innere ==
wird in die CIL ceq übersetzt Code. Mit anderen Worten, es ist primitive CLR-Gleichheit.
Ich war neugierig, ob der C # -Compiler beim Vergleichen von zwei doppelten Werten auf ceq
oder den Operator ==
verweisen würde. Im trivialen Beispiel (unten) habe ich ceq
verwendet.
Dieses Programm:
%Vor% erzeugt die folgende CIL (beachten Sie die Anweisung mit dem Label IL_0017
):
Wie in der Microsoft-Dokumentation für den System.Runtime.Versioning-Namespace angegeben: Die in diesem Namespace gefundenen Typen sind für die Verwendung in .NET Framework und nicht für Benutzeranwendungen gedacht. Der System.Runtime.Versioning-Namespace enthält erweiterte Typen, die unterstützt die Versionierung in parallelen Implementierungen von .NET Framework.
Tags und Links .net c# language-lawyer