Weil der Standard es erlaubt (siehe den zweiten Fall unten):
14.14.2 Zusammengesetzte Zuweisung
Eine Operation der Form
x
op=
y
wird verarbeitet, indem die binäre Operator-Überladungsauflösung (§14.2.4) so angewendet wird, als wäre die Operationx
opy
. Dann,
Wenn der Rückgabetyp des ausgewählten Operators implizit in den Typ
x
konvertiert werden kann, wird die Operation alsx = x
opy
ausgewertet, mit Ausnahme vonx
wird nur einmal ausgewertet.Wenn der ausgewählte Operator ein vordefinierter Operator ist, wenn der Rückgabetyp des ausgewählten Operators explizit in den Typ
x
konvertiert werden kann undy
implizit in den Typ% co_de konvertiert werden kann % oder der Operator ist ein Schichtoperator, dann wird die Operation alsx
opx = (T)(x
ausgewertet, wobeiy)
der Typ vonT
ist, außer dassx
nur ausgewertet wird einmal.- Andernfalls ist die Verbundzuweisung ungültig und es tritt ein Fehler bei der Kompilierung auf.
Der IL-Code sollte in diesem Fall im Wesentlichen identisch sein. Wenn die Auswertung von x
Nebenwirkungen hat, wird sie natürlich zweimal im Fall b
und nur einmal bei Verwendung der Verbundzuweisung ausgewertet.
Dies ist eine FAQ im C # -Tag, die schwer zu finden ist. Die Notwendigkeit der Besetzung ist zuerst relevant. Der Grund dafür ist, dass die CLI nur eine begrenzte Anzahl gültiger Typen für den Befehl Opcodes.Add IL angibt. Es werden nur Operanden vom Typ Int32, Int64, Single, Double und IntPtr unterstützt. IntPtr ist auch etwas Besonderes, die C # -Sprache verbietet es, dieses zu verwenden.
Daher muss der C # -Compiler eine implizite Konvertierung verwenden, um das Byte auf einen Typ zu heben, den der Operator unterstützt. Es wird Int32 als den nächsten kompatiblen Typ auswählen. Das Ergebnis der Addition ist Int32. Das passt nicht zurück in ein Byte, ohne das Ergebnis zu kürzen, und wirft die zusätzlichen Bits weg. Ein offensichtliches Beispiel ist 255 + 1, das Ergebnis ist 256 in Int32, passt aber nicht zu einem Byte und ergibt 0, wenn es gespeichert wird.
Das ist ein Problem. Die Sprachentwickler haben diese Kürzung nicht mögen, ohne dass Sie explizit die Konsequenzen erkannt haben. Eine Umwandlung ist erforderlich, um den Compiler davon zu überzeugen, dass Sie sich dessen bewusst sind. Ein bisschen wie ein Cop-out, natürlich tendierst du dazu, die Besetzung mechanisch zu produzieren, ohne viel über die Konsequenzen nachzudenken. Aber das macht es zu deinem Problem, nicht von Microsoft:)
Das reiben war der + = Operator, ein sehr netter Operator, um den Condense-Code zu schreiben. Ähnelt der Kürze des Schlüsselworts var . Rock und ein harter Ort, wo legst du die Besetzung hin? Es funktioniert einfach nicht, also haben sie das Problem überstanden und das Abschneiden ohne einen Cast erlaubt.
Bemerkenswert ist, wie VB.NET funktioniert, es ist kein Cast erforderlich. Aber es gibt eine Garantie, dass C # nicht standardmäßig zur Verfügung stellt, wird es eine OverflowException generieren, wenn das Ergebnis nicht passt. Ziemlich nett, aber dieser Scheck kommt nicht umsonst.
Saubere Sprachen zu entwerfen ist ein sehr schwieriges Problem. Das C # -Team hat ausgezeichnete Arbeit geleistet, Warzen nicht. Sonst die Art von Warzen durch Prozessor-Design verursacht. IL hat diese Typenbeschränkungen, weil das auch echte 32-Bit-Prozessoren haben, insbesondere die RISC-Designs, die in den 90er Jahren populär waren. Ihre internen Register können nur 32-Bit-Integer und IEEE-754 Fließkommawerte verarbeiten. Und erlauben nur kleinere Arten in Ladungen und Lagern. Der Intel x86-Core ist sehr beliebt und erlaubt eigentlich grundlegende Operationen auf kleineren Typen. Aber das ist meistens ein historischer Unfall, weil Intel das Design durch die 8-Bit-8080- und 16-Bit-8086-Generationen kompatibel hält. Es ist nicht kostenlos, 16-Bit-Operationen kosten einen zusätzlichen CPU-Zyklus. Zu vermeiden.
Die Spezifikation nennt dies als einen speziellen Fall des zusammengesetzten Zuweisungsoperators:
Genauer gesagt, Punkt 2:
Die zweite obige Regel erlaubt es, x op = y als x = (T) (x op y) in bestimmten Kontexten. Die Regel existiert so, dass das vordefinierte Operatoren können als zusammengesetzte Operatoren verwendet werden, wenn der linke Operand ist vom Typ sbyte, byte, short, ushort oder char. Auch wenn beide Argumente Sind einer dieser Typen vorhanden, erzeugen die vordefinierten Operatoren ein Ergebnis vom Typ int, wie in Abschnitt 7.2.6.2 beschrieben. So, ohne es zu werfen Es wäre nicht möglich, das Ergebnis dem linken Operanden zuzuordnen.
Dies aufgrund der impliziten Konvertierungsregeln.
Wenn Sie einen binären Operator +
haben, wird das Ergebnis in den größeren der beiden Typen konvertiert.
Das Literal 200
ist vom Typ int und daher ist der Typ des Ausdrucks b+200
int.
Der Zuweisungsoperator =
führt keine implizite Konvertierung durch, sondern einen Fehler. Wie in
Im zweiten Fall erwartet der Operator +=
das Byte, also wird 200 (das vom Typ int ist, aber in Byte passt) implizit in Byte konvertiert, weil der Compiler es weiß. Folgendes wird nicht kompiliert, da die Kompilierung nicht weiß, ob x in ein Byte passt oder nicht.
Wenn Sie x zu const machen, kompiliert es:
%Vor%