Числа с плавающей точкой в .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;
// Check if the expression a+b would overflow, *without* the need to use
// try/catch around the expression
checkOverflow(() => {checked { return a+b; }});
}
private static void checkOverflow(Func<int> exp)
{
try
{
exp();
}
catch(OverflowException)
{
Console.WriteLine("overflow!");
}
}
Я должен добавить причину, по которой это работает:
флажок не является лексической областью в смысле воздействия на переменные.Это область, интерпретируемая компилятором как говорящая: весь код внутри, который выполняет целочисленную арифметику, должен генерировать команды перехвата переполнения.не имеет значения, откуда берутся переменные, только какой код определен где.
Я полагаю, что ваша ментальная модель похожа на:
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
Это не то, как проверено, работает, проверено определяет, какие инструкции генерируются во время компиляции (некоторые инструкции перехватывают, некоторые нет)
Проверенный блок НЕ влияет на код, определенный вне его.Например, просто используя функции:
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.Таким образом, два обращения к нему не могут изменить его, чтобы проверить или нет по факту.Проверенный блок вокруг первого вызова в приведенном выше примере на самом деле не влияет на результирующий IL.Там нет операций определенных внутри него, которые имеют значение для него.
Таким образом, вашей первоначальной идеей было определить арифметическую операцию в одном месте (без проверки), а затем запустить ее в другой точке (точно так же, каквызов функции), но проверенная инструкция не может повлиять на код, который не был окружен во время компиляции.
лямбда-выражения преобразуются либо в деревья выражений, либо в анонимный делегат (возможно, при поддержке необходимых синтетических классов для хранения и поддержки любых переменных, связанных с замыканием).В обоих случаях проверенный аспект любой их части полностью определяется там, где они определены, а не там, где они вызываются.