在 .Net 中,浮点数不会像整数运算那样溢出。当遇到特定情况时,它们会变成 Double.PositiveIfinity、Double.NegativeIfinity 或 Double.Nan(在数学运算无效的情况下)。请注意,由于浮点数在面对两个精度非常不同的数字时的行为,这也略微复杂。
Console.WriteLine(double.MaxValue);
Console.WriteLine(double.MaxValue * 2);
Console.WriteLine(double.MaxValue + 1);
Console.WriteLine(double.MaxValue + double.MaxValue);
提供:
1.79769313486232E+308
Infinity
1.79769313486232E+308
Infinity
此外,不清楚您的checkOverflow函数的目的是什么,只要写下它发生了什么?如果这就是您想要的,那么这种方法会起作用(我已经为您转换为int)。
void Main()
{
int a, b;
a = int.MaxValue;
b = 1;
checkOverflow(() => {checked { return a+b; }});
}
private static void checkOverflow(Func<int> exp)
{
try
{
exp();
}
catch(OverflowException)
{
Console.WriteLine("overflow!");
}
}
我应该补充一下这个代码为什么能够运行的原因:
checked并不是影响变量的词法作用域,它是编译器解释的一个区域,表示所有在这里进行整数算术运算的
代码都应该生成溢出陷阱指令。变量来自哪里并不重要,只有定义在哪里的代码才是重要的。
我认为你的思维模式可能是这样的:
checked // enter a 'checked' state where all operations
{ // (say on the current thread) are checked
code, function calls, etc. etc
} // leave the checked mode, all operations are now unchecked
这不是 checked 的工作方式,checked 定义了在编译时发出哪些指令(一些指令会触发溢出,而另一些则不会)。
checked 块不会影响其外部定义的代码。例如,只使用函数:
int Times2(int a)
{
return a * 2;
}
void TheresNoDifferenceHere()
{
checked { Times2(int.MaxValue); }
Times2(int.MaxValue);
}
Times2函数调用会被解析为类似以下的内容
IL_0000: nop
IL_0001: ldarg.1
IL_0002: ldc.i4.2
IL_0003: mul
IL_0004: stloc.0
IL_0005: br.s IL_0007
IL_0007: ldloc.0
IL_0008: ret
如果您曾经使用过
int Times2(int a)
{
checked { return a * 2; }
}
IL_0000: nop
IL_0001: nop
IL_0002: ldarg.1
IL_0003: ldc.i4.2
IL_0004: mul.ovf
IL_0005: stloc.0
IL_0006: br.s IL_0008
IL_0008: ldloc.0
IL_0009: ret
请注意使用mul和mul.ovf之间的区别。因此,即使在事后,这两个调用也不能改变其是否被检查。以上示例中第一个调用周围的checked块实际上对生成的IL没有任何影响。其中没有任何一项操作在其内部定义且对其有影响。
因此,您最初的想法是在一个地方(不进行检查)定义算术运算,然后在另一个地方运行它(就像函数调用一样),但是'checked'指令无法影响编译时未包围的代码。
lambda表达式会转换为表达式树或匿名委托(可能由必需的合成类来支持和维护任何与闭包相关的变量)。在两种情况下,它们的任何部分的checked方面完全由它们定义的位置而不是它们被调用的位置定义。
checked { exp(); }
时,溢出没有被捕获,而在lambda中却可以吗?a+b
是在什么时候被计算的? - AndiDog