Les nombres à virgule flottante dans .Net ne débordent pas de la même manière que les nombres arithmétiques entiers.
Ils vont obligeamment à Double.PositiveIfinity, ou Double.NegativeIfinity (spécifique dans les cas où l'opération mathématique devient Double.NaN invalide)
noter que ceci est également un peu plus complexe en raison du comportement à virgule flottante lorsque face à deux chiffres avec une précision très différente.
Console.WriteLine(double.MaxValue);
Console.WriteLine(double.MaxValue * 2);
Console.WriteLine(double.MaxValue + 1);
Console.WriteLine(double.MaxValue + double.MaxValue);
donne:
1.79769313486232E+308
Infinity
1.79769313486232E+308
Infinity
De plus on ne sait pas ce que vous voulez que votre fonction checkOverflow faire, il suffit d'écrire que cela est arrivé?
Si c'est tout cette approche fonctionnera (je converti en int pour vous)
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!");
}
}
Je dois ajouter la raison pour laquelle cela fonctionne:
vérifié n'est pas une portée lexicale dans le sens d'affecter les variables. C'est une région interprétée par le compilateur comme disant, tous code ici à l'intérieur qui fait l'arithmétique entière devrait générer les instructions de piégeage de débordement. Peu importe d'où viennent les variables, seulement quel code est défini où.
Je crois que votre modèle mental est quelque chose comme:
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
Ce n'est pas comment fonctionne vérifié, vérifié définit quelles instructions sont émises au moment de la compilation (un peu trop plein de piège instructions, certains ne le font pas)
Le bloc coché n'affecte PAS le code défini en dehors de celui-ci. Par exemple tout en utilisant les fonctions:
int Times2(int a)
{
return a * 2;
}
void TheresNoDifferenceHere()
{
checked { Times2(int.MaxValue); }
Times2(int.MaxValue);
}
L'appel de la fonction Times2 résout à quelque chose comme
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
Si vous aviez utilisé
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
noter la différence dans l'utilisation de Mul et mul.ovf . Ainsi, les deux appels ne peuvent pas être modifiés pour être vérifiés ou non après le fait. Le bloc coché autour du premier appel dans l'exemple ci-dessus a effectivement aucun effet sur l'IL résultant.Il n'y a pas d'opérations définies à l'intérieur qui lui importent. Ainsi, votre idée originale définissait l'opération arithmétique à un endroit (sans vérification) puis l'exécutait à un autre point (comme un appel de fonction) mais l'instruction 'vérifiée' ne peut pas affecter le code qu'elle n'a pas entouré au moment de la compilation. . Lambdas se résout à des arborescences d'expression ou à un délégué anonyme (peut-être soutenu par les classes synthétiques requises pour conserver et maintenir les variables liées à la fermeture). Dans les deux cas, l'aspect vérifié de n'importe quelle partie d'entre eux est entièrement défini là où ils sont définis, et non là où ils sont appelés.
Pouvez-vous expliquer pourquoi le débordement n'est pas intercepté lors de l'exécution de 'checked {exp(); } 'dans le bloc try * au lieu de * dans le lambda? Quand est-ce que 'a + b' est évalué? – AndiDog
@AndiDog, est-ce que le bit dans mon édition ne m'explique pas assez? Je vais essayer d'ajouter à cela. – ShuggyCoUk
Bon, c'est logique maintenant. Merci – AndiDog