Почему x = x + 100 обрабатывается иначе, чем x + = 100, который компилируется в один и тот же IL? - PullRequest
0 голосов
/ 09 сентября 2018

Мы знаем, что эти два оператора сложения эквивалентны и компилируются в один и тот же код IL:

int x = 100;

x += 100;
x = x + 100;

Однако, когда требуется явное приведение, я заметил нечто странное:

byte b = 100;

b += 200; // Compiles (1)
b = b + 200; // Cannot implicitly convert int to byte (2)
b = (byte) (b + 200); // Compiles (3)

Очевидно, что второе утверждение требует явного приведения, потому что результатом сложения является целое число. Но странная вещь для меня - первое утверждение. Он компилируется в тот же IL, что и третий оператор, поэтому похоже, что компилятор добавляет приведение, которое должно быть явным для нас. Но это не может быть сделано во втором утверждении.

Мне это кажется противоречивым, потому что я ожидаю, что первое утверждение будет эквивалентно второму и никогда не будет компилироваться, так почему оно компилируется?

Примечание: не компилируется, когда требуется явное приведение от long до int:

int x = 100;
long y = 200;

x += y;

1 Ответ

0 голосов
/ 09 сентября 2018

Вам действительно нужно обратиться к спецификациям для получения информации такого рода (и может быть очень трудно разобраться с формулировкой). Впрочем, прямо изо рта лошади

12.18.3 Составное назначение

Операция вида x op= y обрабатывается с применением двоичного разрешение перегрузки оператора (§12.4.5), как если бы операция была написана x op y. Тогда

  • Если тип возвращаемого значения выбранного оператора неявно преобразуется в тип x, операция оценивается как x = x op y, за исключением того, что x вычисляется только один раз.

  • В противном случае, если выбранный оператор является предопределенным оператором, если тип возвращаемого значения выбранного оператора явно преобразуется в тип x, а если y неявно преобразуется в тип x или оператор является оператором сдвига, то операция оценивается как x = (T)(x op y), где T - тип x, за исключением того, что x оценивается только один раз.

  • В противном случае составное присваивание недопустимо и возникает ошибка времени привязки.

...

бла-бла-бла

...

Второе правило выше позволяет x op= y быть оцененным как x = (T)(x op y) в определенных контекстах . Правило существует так, что предопределенные операторы могут использоваться как составные операторы, когда левый операнд типа sbyte, byte, short, ushort или char. Даже когда оба аргументы относятся к одному из этих типов, предопределенные операторы производят результат типа int, как описано в §12.4.7.3. Таким образом, без броска было бы невозможно присвоить результат левому операнду .

Интуитивно понятный эффект правила для предопределенных операторов просто x op= y разрешено, если оба из x op y и x = y разрешено .

byte b = 0;
char ch = '\0';
int i = 0;
b += 1; // Ok
b += 1000; // Error, b = 1000 not permitted
b += i; // Error, b = i not permitted
b += (byte)i; // Ok
ch += 1; // Error, ch = 1 not permitted
ch += (char)1; // Ok

Интуитивная причина каждой ошибки в том, что соответствующая простая назначение также было бы ошибкой.

Короче говоря, компьютер говорит нет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...