Номера с плавающей точкой в .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 делать, просто написать, что это произошло?
Если это все, этот подход будет работать (я преобразовал в целое для вас)
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.ovf , Таким образом, два вызова к нему не могут изменить его, чтобы его проверить или нет после факта. Проверенный блок вокруг первого вызова в приведенном выше примере фактически имеет без эффекта на полученном ИЛ.Нет операций определяется внутри этого, что имеет значение для него.
Таким образом, ваша первоначальная идея заключалась в определении арифметической операции в одном месте (без проверки), а затем ее в другой точке (как вызов функции), но команда «checked» не может повлиять на код, который он не окружал во время компиляции ,
lambdas разрешает работу с деревьями выражений или анонимным делегатом (возможно, поддерживаются требуемыми синтетическими классами для хранения и поддержки любых связанных с закрытием переменных). В обоих случаях проверенный аспект любой части из них полностью определен там, где они определены, а не там, где они вызываются.
Можете ли вы объяснить, почему переполнение не поймано при выполнении 'checked {exp(); } 'в блоке try * вместо * в лямбда? Когда оценивается 'a + b'? – AndiDog
@ AndiDog, бит в моем редактировании не достаточно объясняет? Я постараюсь добавить к нему. – ShuggyCoUk
Хорошо, теперь имеет смысл. благодаря – AndiDog