C#不允许我将两个short类型的数相加得到一个short类型的结果

19

我有一段代码:

static short Sum(short a, short b)
        {
            return a + b;
        }

它无法编译,说是不能将'int'转换为'short'。 今天或许我真的很累,但我找不出问题!


这是你的答案。 - user1071979
3个回答

32

但它无法编译,提示无法将'int'转换为'short'。也许我今天真的很累,但我看不出问题所在!

这只是语言定义的方式。整数类型的+操作符定义为:

static uint op +(uint x, uint y)
static int op +(int x, int y)
static ulong op +(ulong x, ulong y)
static long op +(long x, long y)

操作数会根据需要提升。

至于为什么以这种方式定义 - 老实说我不知道。我不认同“因为可能会溢出”的论点 - 这意味着byte + byte 应该被定义为返回 short,而int + int应该返回long,但事实并非如此。

我听说过这可能与性能有关,但我不能确定。(也许处理器通常只在32位和64位整数上提供整数运算?)

无论如何,为什么会这样并不是很重要 - 这只是语言规则。

请注意,复合赋值运算符具有对相关类型的隐式转换,所以你可以编写:

short x = 10;
short y = 20;
x += y;

1
@JonSkeet 那样也无法编译(运算顺序)。你需要用括号将加法包起来。 - Servy
1
Jon - 我为自己辩护:https://dev59.com/wG855IYBdhLWcg3wbzxl#4347752 - Oded
4
@Oded:说得也有道理,但在这种情况下,即使这意味着不同意Eric,它仍然感觉像是一个薄弱的论点。我要走了。 - Jon Skeet
@JonSkeet(抱歉耽搁了),实际上并不需要太多的修改,他们本来就已经在32位数学运算上实现了16位数学运算,只是在正确的地方抛弃掉了顶部一半(我认为主要是在右移、除法和模运算之前)。这并不会对性能造成太大影响。 - harold
如果有人仍然想知道,这里详细解释了:https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/expressions#addition-operator - Don Box
显示剩余5条评论

9
当你把两个short相加时,它们的总和可能会超过short的最大值,但对于int来说是可以的。这基本上就是Eric Lippert在他这里的回答中所说的。
附:为什么两个int相加不返回long?Eric 也解释了:

在一个整数算术环境下,将所有计算都转换为int更加明智,因为int类型可能具有足够的范围,使得典型的计算不会溢出。


由于这个原因,定义在两个short相加时的"+"运算符返回一个int。
这就是为什么你会得到编译时错误-你正在返回一个int,而指定的返回类型为short。
如果你"知道"相加总会得到一个short,那么可以将结果显式地强制转换为short。
static short Sum(short a, short b)
{
    return (short)(a + b);
}

2
这是一个不允许你将两个int值相加得到另一个int值的论点。 - Jon Skeet
是的,它们可以,但不一定需要。我可以使用整数来实现,同时期望一个长整型。 - John V
2
@JonSkeet 啊,但那种情况发生的机会只有一半那么大。 - Mr Lister
你可能期望得到一个更大的long值,但实际上不会。如果你将int.MaxValue和1相加,你得到的不是一个比int.MaxValue更大的long值,而是int.MinValue。 - Jon Skeet
@user970696 - 是的,但这不是语言的工作方式。设计者决定允许int溢出,但不允许short - Oded

0

Jon Skeet已经详细解释了为什么你的代码无法工作,但他没有列出你需要做什么才能使其编译。你可以使用以下方法:

static short Sum(short a, short b)
{
    return (short)(a + b);
}

没关系,我只是在寻找一种简单地造成溢出异常的方法而已 ;) - John V
你应该考虑到这样的情况:short x + short y 超过了 short 类型的最大值,让它抛出一个异常。@user970696 造成溢出异常最简单的方法就是直接使用 throw new OverflowException(); - aevitas
@aevitas 这取决于是否需要抛出异常。无论哪种情况,您都应该在代码周围使用checkedunchecked块来获得所需的行为,而不是手动检查并抛出异常。 - Servy
我正在寻找如何使C#自然地引发异常,而不是通过使用内置机制来强制它。 - John V
@user970696 - 你可以使用checked关键字来实现。 - Oded
1
是的,return checked((short)(x + y)); - Jeppe Stig Nielsen

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