12

こんにちは、Enumerable.Sum()LINQ の拡張メソッドを使用してハッシュ コードを計算しOverflowExceptionsていますが、コードが大きくなると問題が発生します。呼び出しをブロックに入れようとしましたuncheckedが、それは役に立たなかったようです。

メソッドのMSDNドキュメントには、値が大きくなりすぎるとスローされると書かれていますが、リフレクターをチェックインしたところ、これだけです:

public static int Sum(this IEnumerable<int> source) {
    if (source == null) {
        throw Error.ArgumentNull("source");
    }
    int num = 0;
    foreach (int num2 in source) {
        num += num2;
    }
    return num;
}

この逆コンパイルに基づいて、呼び出し元のコードのコンテキストに応じて、オーバーフローするかどうかが予想されます。オーバーフローするのはなぜですか? また、どうすればオーバーフローを止めることができますか?

4

3 に答える 3

9

コードは実際に C#checkedブロックで実行されています。問題は、リフレクターがブロックを適切に逆コンパイルせずchecked、代わりに通常の数学演算として表示することです。チェックされたブロックを作成し、コードをコンパイルしてからリフレクターで逆コンパイルすることで、これを自分で確認できます。

逆コンパイルされた C# コードの代わりに IL を見て、これを確認することもできます。add IL オペコードの代わりに、add.ovf で追加が行われることがわかります。これは、オーバーフローをスローする add のバージョンです

L_001a: callvirt instance !0 [mscorlib]System.Collections.Generic.IEnumerator`1<int32>::get_Current()
L_001f: stloc.1 
L_0020: ldloc.0 
L_0021: ldloc.1 
L_0022: add.ovf <-- This is an overflow aware addition
L_0023: stloc.0 
L_0024: ldloc.2 

この特定のメソッドがオーバーフローでスローされないようにする方法はありません。あなたの最良の選択肢は次のとおりです

  1. 次のようなより大きなタイプに切り替えますlong
  2. チェック加算を使用しない独自のバージョンの Sum を作成する
于 2010-02-05T17:01:03.407 に答える
7

この関数は、一般的な列挙型用に作成しました。それについて何か意見があれば聞きたいです。

public static int SequenceHashCode<T>(IEnumerable<T> seq)
{
    unchecked
    {
        return seq != null ? seq.Aggregate(0, (sum,obj) => sum+obj.GetHashCode()) : 0;
    }
}
于 2013-04-03T12:13:19.203 に答える
1

checked現在のブロック内の式にのみ適用され、(既にコンパイルされた) 呼び出されたメソッドには適用されません。チェックされていない数学を使用するには、ブロックSum内に独自のバージョンを実装する必要がありますunchecked

于 2010-02-05T17:05:31.067 に答える