未检查的块对BigInteger不起作用

本文关键字:BigInteger 不起作用 检查 | 更新日期: 2023-09-27 18:06:44

刚才注意到未检查的上下文在处理BigInteger时不起作用,例如:

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

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

谢谢,

未检查的块对BigInteger不起作用

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

long long2 = (long)bigInt;

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

它无法到达该方法内部并告诉它停止抛出异常。

但是当编译器看到
int x = (int) someLong;

编译器生成进行转换的代码,因此它可以选择生成它认为合适的检查或未检查的代码。

记住,"选中"answers"未选中"在运行时没有影响;当控件进入未检查的上下文时,CLR不会进入"未检查模式"。"checked"answers"unchecked"是对编译器的指令,指示在块中生成哪种代码。它们只在编译时起作用,并且BigInt转换为long的编译已经发生了。它的行为是固定的

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

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

换句话说,它以方式处理溢出,而不管checkedunchecked上下文的。医生是这么说的

更新:当然,Eric是这个问题的最终定论。请去看他的帖子:)

文档明确指出在这种情况下它将抛出OverflowException。被检查的上下文只对c#编译器发出的"本地"算术运算有影响——不包括调用显式转换操作符。

要"安全地"执行转换,您必须首先将其与long.MaxValuelong.MinValue进行比较,以检查它是否在范围内。为了获得溢出到负的效果,我怀疑您必须首先在BigInteger中执行use位操作符。例如:

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