Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

unchecked block doesn't work with BigInteger?

Just noticed that the unchecked context doesn't work when working with a BigInteger, for instance:

unchecked
{
    // no exception, long1 assigned to -1 as expected
    var long1 = (long)ulong.Parse(ulong.MaxValue.ToString());
}

unchecked
{
    var bigInt = BigInteger.Parse(ulong.MaxValue.ToString());

    // throws overflow exception
    var long2 = (long)bigInt;
}

Any idea why that's the case? Is there something special with the way big integers are converted to other primitive integer types?

Thanks,

like image 912
theburningmonk Avatar asked Nov 29 '22 10:11

theburningmonk


1 Answers

The C# compiler has no idea whatsoever that a BigInteger is logically an "integral type". It just sees a user-defined type with a user-defined explicit conversion to long. From the compiler's point of view,

long long2 = (long)bigInt;

is exactly the same as:

long long2 = someObject.SomeMethodWithAFunnyNameThatReturnsALong();

It has no ability to reach inside that method and tell it to stop throwing exceptions.

But when the compiler sees

int x = (int) someLong;

the compiler is generating the code doing the conversion, so it can choose to generate checked or unchecked code as it sees fit.

Remember, "checked" and "unchecked" have no effect at runtime; it's not like the CLR goes into "unchecked mode" when control enters an unchecked context. "checked" and "unchecked" are instructions to the compiler about what sort of code to generate inside the block. They only have an effect at compile time, and the compilation of the BigInt conversion to long has already happened. Its behaviour is fixed.

like image 135
Eric Lippert Avatar answered Dec 23 '22 15:12

Eric Lippert