注意到使用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;
}
知道为什么会这样吗?大整数转换为其他原始整数类型的方式有什么特别之处吗?
谢谢,
答案 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.MaxValue
和long.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);
}
}
}