Definition des Operators "==" für Double

122

Aus irgendeinem Grund schlich ich mich in die .NET Framework-Quelle für die Klasse Double und fand heraus, dass die Deklaration von == lautet:

%Vor%

Dieselbe Logik gilt für jeder -Operator.

  • Was ist der Sinn einer solchen Definition?
  • Wie funktioniert es?
  • Warum erstellt es keine unendliche Rekursion?
Thomas Ayoub 01.02.2016, 15:04
quelle

5 Antworten

60

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):

%Vor%

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 "?

    
D Stanley 01.02.2016, 15:22
quelle
37

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 #.

    
Luaan 01.02.2016 16:37
quelle
12

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.

    
taffer 01.02.2016 15:30
quelle
8

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 ):

%Vor%     
Daniel Pratt 01.02.2016 15:22
quelle
0

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.

    
Thomas Papamihos 03.02.2016 09:17
quelle

Tags und Links