如何在 C# 中减去一行中的字节

问题描述 投票:0回答:3

这真的很奇怪。 谁能解释一下这个吗?

此代码不起作用:

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;

如果必须的话,我不介意将这些陈述放在单独的行中......但我不得不想知道......

为什么?

c# language-construct
3个回答
7
投票

这是因为 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/publications/files/ECMA-ST/Ecma-334.pdf

14.14.2 复合赋值:

x op= y 形式的运算是 通过应用二元运算符进行处理 重载解析(§14.2.4)就像 该操作被写为 x op y。 然后,

• 如果返回类型 选择的运算符是隐式的 可转换为 x 的类型, 操作计算为 x = x op y, 除了 x 仅评估一次。

否则,如果所选运算符是预定义运算符,并且所选运算符的返回类型可显式转换为 x 的类型,并且 y 可以隐式转换为 x 的类型或者该运算符是移位运算符,那么该操作的计算结果为 x = (T)(x op y),其中 T 是 x 的类型,但 x 仅计算一次。

• 否则,复合赋值是 无效,并且出现编译时错误 发生


5
投票

前两个示例无法编译的原因是:

  • 强制转换比减法结合得“更紧”。 也就是说,“(C)d-e”表示“((C)d)-e”,而不是“(C)(d-e)”。强制转换运算符的优先级更高。
  • 因此,无论进行何种类型转换,减法的两个操作数的类型都是字节。
  • 减法的类型是int,因为没有在字节上定义减法运算符。
  • 因此,您将 int 分配给字节而不进行强制转换,这是非法的。

字节上没有减法运算符,因为假设您有一个包含 7 的字节,并从中减去一个包含 8 的字节,您真的希望它成为字节 255 吗?我想大多数人会希望它是 int -1。

最后,你到底为什么要以字节为单位这样做?这没有任何意义。 C# 中的字符不是字节;如果你想对字符进行算术那么为什么不从字符'y'中减去char 96而不是进行有损且危险的字节转换?


4
投票

我之前也注意到了这一点。我认为这是因为

-=
运算符是为字节类型预定义的,而在前一种情况下,您实际上是将
int
放在
byte
中,这是不允许的。他们这样做的原因不一定有意义,但它符合规则,因为在前一种情况下,编译器在进行赋值时无法“偷看”
-
运算符。

如果你确实需要在一行上进行减法,而不是说:

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

说:

byte c7 = (byte)(Upright[6] - ASC_OFFSET);
© www.soinside.com 2019 - 2024. All rights reserved.