Reputation: 7148
I am having a hard time determining if a checked
operation on an int
using a Func<int, int>
resulted in an overflow or underflow. If I do not use a Func<int, int>
I have found a way to determine this
int _Data = Data; // Data is some integer value
int scaleValue = int.MaxValue; // Just for completion, could be any value
try
{
checked
{
Data *= scaleValue;
}
}
catch (System.OverflowException ex)
{
// Cast the values to float so we can operate beyond the integer range
// This way we can check if we went over Max or Min Values
if ((float)_Data * (float)scaleValue > int.MaxValue)
Data = int.MaxValue;
else
Data = int.MinValue;
}
Though if I do use a Func<int, int>
then I cannot use my trick above to determine the outcome.
int _Data = Data;
Func<int, int> scaleFunction = (x) => (x * int.MaxValue);
try
{
checked
{
Data = scaleFunction(Data);
}
}
catch (System.OverflowException ex)
{
// How to tell if scaleFunction created under or over flow?
if ((float)_Data * (float)scaleValue > int.MaxValue)
Data = int.MaxValue;
else
Data = int.MinValue;
}
The only option I see is to "alter" the given Func<int, int>
to work on float
, but if the structure of the Func<int, int>
is not known before hand then I do not think it can be changed.
Can anyone see a sneaky way to accomplish this?
This is the thread where I found the original sneaky operation: Determine if integer overflow is over or under bounds
Here is a related question I asked earlier that gives some more background: Determine if operation will result in overflow?
EDIT: In my usage of this code I will not have control over the way that the Func<int, int>
is created. Thus I cannot put a check
expression or blocked inside of it.
I also did not realize that check
does not check for overflow "inside functions" that are used within it. If this is so, I think that this problem is much harder. As a result of not being able to modify the Func
to use check
we have to do the check by hand.
The issue with doing it by hand is that it (to me currently) seems impossible. It might make sense to use the trick of checking whether the original value has the same sign as the output value from the Func
. The issue is that you cannot tell if the Func
increased the value past the max illegally, or if it decreased the value below 0 legally; or vise versa.
Upvotes: 3
Views: 101
Reputation: 171246
In my usage of this code I will not have control over the way that the Func is created. Thus I cannot put a check expression or blocked inside of it.
Then, you have lost.
checked/unchecked
is a property of any individual arithmetic instruction at the IL level. It is not flowed across method calls. It is not a setting that you can switch on or off. It is compiled into the .NET binary for each instruction individually.
The author of any piece of code decides the checked
property and it cannot be altered.
In fact it would be dangerous and unreliable if you could reach into other peoples code and subtly alter the behavior of basic arithmetic instructions.
Upvotes: 4
Reputation: 4992
checked
blocks or expressions (both flavors exist and have identical effects) are not "inherited" by called methods, so your lambda is actually multiplying in unchecked context.
Try the following instead:
int _Data = Data;
Func<int, int> scaleFunction = (x) => checked(x * int.MaxValue);
try
{
Data = scaleFunction(Data);
}
catch (System.OverflowException ex)
{
// handle overflow...
}
Upvotes: 1