当在C#中需要基值类型的强制转换时

本文关键字:转换 类型 当在 | 更新日期: 2023-09-27 18:26:11

当使用数学运算时,我有一个关于在基值类型之间转换的一般问题。微软C#规范中有书面规则吗?我找不到他们。它在Mono中也一样吗?

示例:

double a = 1 / 1234;                    //Result is 0
double b = 1.0 / 1234;                  //Result is 0,000810372771474878
double c = 1.0 / (double)1234;          //Result is 0,000810372771474878
double d = (double)1 / (double)1234;    //Result is 0,000810372771474878
double e = 1 / 1234.0;                  //Result is 0,000810372771474878

当被除数或除数是双时,我能假设结果总是双吗?或者出于某种原因,最好确保两者都是双重的(见案例d-我见过很多这样的代码,实际上让我问这个问题)

谨致问候,Sebastian

当在C#中需要基值类型的强制转换时

长话短说,是的,当二进制操作的至少一侧被键入时,可以安全地假设编译器将假定double。你不需要明确(当然,从可读性的角度来看,有时它可能很有用,这并不真正相关,但值得一提)。

需要明确的是,尽管我认为你在最初的问题中没有混淆这一点,但你分配结果的变量类型对除法运算符过载的确定方式没有影响。

您的top case只是使用了一个隐式转换,它将具有与此显式等价的转换。

double a = (double)(1 / 1234);

将其分配给double的事实不会影响1 / 1234计算为0的事实,正如您所发现的那样,因为该强制转换是在除法之后发生的。如果我们在这里的时空中切开一个洞,这个例子将落在这篇文章底部列表的最后一种情况下,其中两个整数被除以。因此,根据规范第7.8.2节,这将返回商的底数或0


这种行为在C#5规范的7.3.6节中有描述(我承认,这花了一些时间),重点是我的。

7.3.6数字促销

当重载解析规则(§7.5.3)应用于这组运算符时,其效果是从操作数类型中选择存在隐式转换的第一个运算符。例如,对于操作b*s,其中b是字节,s是短运算符,重载解析选择运算符*(int,int)作为最佳运算符。因此,效果是b和s被转换为int,结果的类型是int。同样,对于运算i*d,其中i是int,d是double,重载解析选择运算符*(double,double)作为最佳运算符

当然,这不仅适用于乘法,正如它的例子所示,也适用于任何二进制运算。

为了更好地衡量,层次结构如下,取自7.3.6.2,重点仍然是我的。

•如果其中一个操作数是十进制类型,则另一个操作数会转换为十进制类型,或者如果另一个运算数是浮点或双精度类型,则会发生绑定时间错误
否则,如果任一操作数的类型为double,则另一个操作数将转换为double类型
•否则,如果其中一个操作数的类型为float,则另一操作数将转换为float类型
•否则,如果其中一个操作数的类型为ulong,则另一个操作数会转换为ulong类型;如果另一个操作数的类型是sbyte、short、int或long,则会发生绑定时间错误
•否则,如果任一操作数的类型为long,则另一个操作数将转换为long类型
•否则,如果任一操作数的类型为uint,另一个操作数类型为sbyte、short或int,则两个操作数都将转换为long类型
•否则,如果任一操作数的类型为uint,则另一个操作数将转换为uint类型
•否则,两个操作数都转换为int类型。

实际上,编译器通过将非double操作数转换为类型double,实际上为您执行了转换。

当您将两个整数进行除法时,会得到一个整数结果。由于int不能容纳0,000810372771474878,因此结果将被截断为0,然后0(int)被转换为double,得到0.0作为结果。

为了获得浮点结果,其中一个操作数应该是浮点类型。在这种情况下,整数操作数将转换为double/floatdecimal,具体取决于数字的类型。

C# Specification 7.7.2 Division operator 中有关于除法运算符的详细信息