Why does this throw an OverflowException?

7.4k views Asked by At

I have the following code in a method to convert any number in to a byte:

try {
    return (byte) Convert.ChangeType(operand.RealValue, TypeCode.Byte);
}
catch (OverflowException) {
    if (AllowArithmeticOverflow) {
        unchecked {
            decimal d = Convert.ToDecimal(operand.RealValue);
            return (byte) d;
        }
    }

    throw;
}

In this code, operand.RealValue is expected to be any number. For the example I'm testing with, it's an sbyte with the value -13 (verified with the debugger). I can step through in the debugger and get to the line return (byte) d; ... At which point an OverflowException is thrown, despite it being in the unchecked block.

So... What gives?

Also, if you're looking at my implementation and wondering what the hell I'm doing - it's the result of all the gymnastics I've tried so far to not get this exception. Must succinct answer wins :)

Note: The exception message is as follows:

System.OverflowException: Value was either too large or too small for an unsigned byte. ---> System.OverflowException: Value was either too large or too small for a UInt32.

3

There are 3 answers

0
Mike Dinescu On BEST ANSWER

Obviously there is no way to interpret -13 as a byte. At least not unless you specify some extra context. Perhaps you mean to treat -13 as an unsigned char (value between -128 and 127) and then reinterpret the bits as a signed char (byte).

If that's what you are trying to do then you could use the BitConverter class.

1
Simon Whitehead On

The exception is caused by using Convert.ChangeType.. which is why the unchecked block may not be working in various circumstances (and why you're no doubt posting this question).

Convert.ChangeType ends up calling IConvertible.To<TypeHere>. The ToByte method on System.SByte is like this:

public static byte ToByte(sbyte value) {
    if (value < 0) {
        throw new OverflowException(Environment.GetResourceString("Overflow_Byte"));
    }

    return (byte)value;
}

It's explicitly throwing the exception.. hence why unchecked is useless.

3
poy On

From your comment:

basically just reinterpret_cast it...

I gather that you want to convert a sbyte with a value -13 and interpret that as a byte.

So simply cast it:

sbyte s = -13;
byte u = (byte)s; // u = 243