4

たとえば、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;
}

なぜそうなのか、何か考えはありますか?大きな整数を他のプリミティブ整数型に変換する方法に何か特別なものはありますか?

ありがとう、

4

3 に答える 3

18

C#コンパイラは、BigIntegerが論理的に「整数型」であることをまったく認識していません。longへのユーザー定義の明示的な変換を伴うユーザー定義の型が表示されるだけです。コンパイラの観点から、

long long2 = (long)bigInt;

とまったく同じです:

long long2 = someObject.SomeMethodWithAFunnyNameThatReturnsALong();

そのメソッドの内部に到達して、例外のスローを停止するように指示することはできません。

しかし、コンパイラが

int x = (int) someLong;

コンパイラーは変換を行うコードを生成しているため、適切と思われる場合は、チェックされたコードとチェックされていないコードのどちらを生成するかを選択できます。

「チェック済み」と「チェックなし」は実行時に効果がないことを忘れないでください。コントロールがチェックされていないコンテキストに入ったときにCLRが「チェックされていないモード」になるのとは異なります。「チェック済み」と「チェックなし」は、ブロック内で生成するコードの種類に関するコンパイラーへの指示です。これらはコンパイル時にのみ効果があり、BigInt変換のlongへのコンパイルはすでに行われています。その動作は修正されています。

于 2011-08-27T13:40:00.090 に答える
4

は、OverflowExceptionで定義された明示的なキャスト演算子によって実際にスローされていBigIntegerます。次のようになります。

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

つまり、またはコンテキストに関係なく、この方法でオーバーフローを処理します。ドキュメントは実際にそう言っています。checkedunchecked

更新:もちろん、エリックはこれに関する最後の言葉です。彼の投稿を読んでください:)

于 2011-08-27T13:36:51.503 に答える
2

ドキュメントには、この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);
        }
    }
}
于 2011-08-27T13:42:59.777 に答える