未选中的块不适用于BigInteger?

时间:2011-08-27 13:30:57

标签: c# c#-4.0 biginteger unchecked

注意到使用BigInteger时unchecked上下文不起作用,例如:

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;
}

知道为什么会这样吗?大整数转换为其他原始整数类型的方式有什么特别之处吗?

谢谢,

3 个答案:

答案 0 :(得分:18)

C#编译器不知道BigInteger在逻辑上是一个“整数类型”。它只是看到一个用户定义的类型,用户定义的显式转换为long。从编译器的角度来看,

long long2 = (long)bigInt;

与:

完全相同
long long2 = someObject.SomeMethodWithAFunnyNameThatReturnsALong();

它无法进入该方法并告诉它停止抛出异常。

但是当编译器看到

int x = (int) someLong;
编译器正在生成执行转换的代码,因此它可以选择生成已检查或未选中的代码。

请记住,“已检查”和“未选中”在运行时无效;当控件进入未经检查的上下文时,它不像CLR进入“未选中模式”。 “checked”和“unchecked”是编译器关于在块内生成什么类型​​的代码的指令。它们只在编译时有效,并且BigInt转换为long的编译已经发生。它的行为是固定的。

答案 1 :(得分:4)

OverflowException实际上是由BigInteger上定义的显式强制转换操作符抛出的。它看起来像这样:

int num = BigInteger.Length(value._bits);
if (num > 2)
{
    throw new OverflowException(SR.GetString("Overflow_Int64"));
}

换句话说,无论<{1}}或checked上下文,它都会以这种方式处理溢出The docs actually say so.

更新:当然,Eric就是最后一句话。请阅读他的帖子:))

答案 2 :(得分:2)

documentation明确声明它会在这种情况下抛出OverflowException。选中的上下文仅对C#编译器发出的“本机”算术运算产生影响 - 不包括调用显式转换运算符。

要“安全”执行转换,您必须首先将其与long.MaxValuelong.MinValue进行比较,以检查它是否在范围内。为了获得溢出到负面效果,我怀疑你必须首先在BigInteger内执行按位运算符。例如:

using System;
using System.Numerics;

class Program
{
    static void Main(string[] args)
    {
        BigInteger bigValue = new BigInteger(ulong.MaxValue);

        long x = ConvertToInt64Unchecked(bigValue);
        Console.WriteLine(x);
    }

    private static readonly BigInteger MaxUInt64AsBigInteger
        = ulong.MaxValue;

    private static long ConvertToInt64Unchecked(BigInteger input)
    {
        unchecked
        {
            return (long) (ulong) (input & MaxUInt64AsBigInteger);
        }
    }
}