为什么我的两个short相加导致强制转换编译错误因为int?

3

在我的代码中,我有以下代码:

Order = config.DeploymentSteps.Select(x => x.Order).DefaultIfEmpty().Max() + 1;

这个错误信息是无法隐式将类型 'int' 转换为 'short'。参考一下,Orderx.Order都是short类型的,Max()正确地返回了一个short类型(我已经验证过了)。所以我理解,它认为1是一个整数类型并引发了错误。于是我把代码改成了:

Order = config.DeploymentSteps.Select(x => x.Order).DefaultIfEmpty().Max() + (short)1;

我现在还是得到了相同的编译错误。也许它没有正确地进行类型转换,所以我尝试将其更改为

Order = config.DeploymentSteps.Select(x => x.Order).DefaultIfEmpty().Max() + Convert.ToInt16(1);

然而我仍然收到相同的错误。最终,我通过转换整个表达式使其工作:

Order = Convert.ToInt16(config.DeploymentSteps.Select(x => x.Order).DefaultIfEmpty().Max() + 1);

为什么我不能直接将1强制转换为short类型并加到另一个short类型上而不是整个内容都要进行强制转换呢?

public short Order { get; set; } 在两个类中。 - KallDrexx
可能是[整数求和问题,short += short的问题]的重复。 (https://dev59.com/wG855IYBdhLWcg3wbzxl) - p.campbell
3个回答

5
这是因为short + short = int。Eric Lippert在这里解释了这个问题。他说:“为什么short加short的结果是int呢?假设short加short还是short,看看会发生什么:short [] prices = {10000,15000,11000}; short average = (prices [0] + prices [1] + prices [2]) / 3; 如果这个计算使用short进行,平均值当然是-9845。总和大于最大可能的short,所以它会变成负数,然后你除以这个负数。在一个整数算术环绕的世界中,将所有计算都用int类型来做要更加明智,因为int类型的范围足够大,可以避免typical calculations to not overflow。

2
这个解释并不真正说明为什么 int + int = int 而不是 long。真正的原因是 CLI 只允许在 Opcodes.Add 指令上使用有限数量的类型。包括 Int、Long、Float、Double 和 IntPtr。如果必要,操作数必须被提升以使它们匹配。C# 语言设计者确实决定不会将结果静默地截断回较小的类型,这与 vb.net 设计者不同。 - Hans Passant
1
@Hans:整数的范围在十亿级别。如果你是那种可能会溢出 int 的整数运算类型的人,那么你应该首先使用 longs - Eric Lippert
3
如果你是那种可能会溢出short类型的算术运算的人,那么你应该一开始就使用int类型。同样正确。这不是编译器在胡乱干预愚蠢程序员,事实上,没有办法将两个short类型相加,因此不能生成相应的代码。编译器可以对无法容纳的结果做出选择。 - Hans Passant
6
@Hans:我不明白可用的IL操作与任何事情有关。没有一种IL操作码可以将两个小数加在一起,但我们在C#中欣然允许这样做。对于可空算术,也没有IL操作码,但我们同样欣然允许。C#语义是针对C#用户的典型使用情况场景设计的,而不是针对可用操作码而设计的。如果有很多C#用户会使用短整型进行算术运算,我们会确保有内置的短整型运算符,而不管我们需要生成什么样的IL代码,就像我们为十进制数所做的那样。 - Eric Lippert
2
@Hans:当然,性能在设计中是一个因素。C#选择默认情况下使用未检查的32位算术,这在很大程度上是因为在大多数芯片上,JIT编译的代码速度快,而不是因为恰好有一个IL指令可用。我只是不明白你的论点,即C#语义是由可用的操作码驱动的。请记住,我们都在同一个部门里;如果早期的C#设计者认为我们需要一个IL操作码来添加两个shorts,那么CLR就会有这样的操作码! - Eric Lippert
显示剩余4条评论

1

C# 语言规范(下载链接) 列出了预定义的加法运算符。对于整数类型,它们包括:

int operator +(int x, int y);
uint operator +(uint x, uint y);
long operator +(long x, long y);
ulong operator +(ulong x, ulong y);

你需要进行强制类型转换的原因是因为没有特定的运算符来添加shorts。我知道“因为C#是这样设计的”并不是一个特别有用的答案,但是就是这样。我建议使用以下代码:
Order = (short) config.DeploymentSteps.Select(x => x.Order).DefaultIfEmpty().Max() + 1;

或者:

Order = config.DeploymentSteps.Select(x => x.Order).DefaultIfEmpty().Max();
Order++;

1

虽然听起来有些冗余,但您介意声明一个短变量(或者可能是常量),并将其初始化为1,在分配订单变量时使用它。与int或long不同,没有一种字面上指定short的方式。


问题在于这些是短整型,因为我的数据库字段为 smallInt - KallDrexx
明白了。但是如果你不能更改它,你仍然没有解决方案,对吧?这就是为什么我建议你在进行选择时使用一个短语,例如:Order = config.DeploymentSteps.Select(x => x.Order).DefaultIfEmpty().Max() + yourShortVariableOrConst; // 其中yourShortVariableOrConst初始化为1 - Arun
为什么我的最终代码不能满足我的需求,其中整个操作都在 Convert.ToInt16 中? - KallDrexx
在你的最终代码中,你试图转换选择方法输出的结果。然而,问题并不在那里。问题出在加法操作符上,它尝试将short类型与int类型相加(字面量1被默认为int类型)。 - Arun

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接