Как вычесть байты на одной строке в C # - PullRequest
5 голосов
/ 02 января 2011

Это действительно странно. Кто-нибудь может объяснить это?

Этот код НЕ работает:

const byte ASC_OFFSET = 96;
string Upright = "firefly";
byte c7 = (byte)Upright[6] - ASC_OFFSET;
//Cannot implicitly convert type 'int' to 'byte'.

Этот код также НЕ работает:

const byte ASC_OFFSET = 96;
string Upright = "firefly";
byte c7 = (byte)Upright[6] - (byte)ASC_OFFSET;
//Cannot implicitly convert type 'int' to 'byte'.

Тем не менее, вычитание в отдельной строке работает просто отлично:

const byte ASC_OFFSET = 96;
string Upright = "firefly";
byte c7 = (byte)Upright[6];
c7 -= ASC_OFFSET;

Я не против поместить утверждения в отдельные строки, если мне придется ... но я должен задаться вопросом ...

Почему?

Ответы [ 3 ]

7 голосов
/ 02 января 2011

Это потому, что 1) byte операции приводят к int (см. Почему здесь: http://blogs.msdn.com/b/oldnewthing/archive/2004/03/10/87247.aspx) и 2) следующий код C #

c7 -= ASC_OFFSET;

будет "магически" скомпилирован за сценой в

c7 = (byte)(c7 - ASC_OFFSET);

Это подробно описано в спецификации C # здесь: http://www.ecma -international.org / публикации / файлы / ECMA-ST / Ecma-334.pdf

14.14.2 Составное назначение:

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

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

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

• В противном случае составное присваивание неверно, и ошибка времени компиляции * происходит * 1027

4 голосов
/ 02 января 2011

Причина, по которой ваши первые два семпла не компилируются, заключается в том, что:

  • Приведение связывает "более плотно", чем вычитание.То есть '(C) de' означает '((C) d) -e', а не '(C) (de)'.Оператор приведения имеет более высокий приоритет.
  • Поэтому тип обоих операндов для вычитания является байтовым, независимо от приведений.
  • Тип вычитания - int, потому что нет оператора вычитанияопределено в байтах.
  • Таким образом, вы присваиваете байту целое число без приведения, что недопустимо.

В байтах нет оператора вычитания, поскольку, предположим, выесть байт, содержащий 7, и вы вычитаете из него байт, содержащий 8, вы действительно хотите, чтобы это был байт 255?Я думаю, что большинство людей хотели бы, чтобы это был int -1.

Наконец, с какой стати ты вообще делаешь это в байтах?Это не имеет никакого смысла.Символы не являются байтами в C #;если вы хотите сделать арифметику с символами, то почему бы не вычесть char 96 из символа 'y' вместо выполнения преобразования с потерями и опасного преобразования в байт?

3 голосов
/ 02 января 2011

Я тоже заметил это раньше. Я думаю, это потому, что оператор -= предопределен для байтовых типов, тогда как в первых случаях вы действительно помещаете int в byte, что недопустимо. Причина, по которой они сделали это, не обязательно имеет смысл, но это согласуется с правилами, поскольку в первых случаях компилятор не может «заглядывать» в оператор - при выполнении присваивания.

Если вам действительно нужно вычесть одну строку, вместо того, чтобы сказать:

byte c7 = (byte)Upright[6] - ASC_OFFSET;

Скажи:

byte c7 = (byte)(Upright[6] - ASC_OFFSET);
...