4

ディクショナリからキーを列挙するディクショナリに関係する不思議な状況がありますが、ディクショナリには含まれているキーの一部が含まれていません。

Dictionary<uint, float> dict = GetDictionary(); // Gets values, 6268 pairs
foreach(uint key in dict.Keys)
{
   if (!dict.ContainsKey(key))
      Console.WriteLine("Wat? "+key);
}

上記は、6268 キーのうちの 2 つを表示します。Int32.MaxValue (369099203 と 520093968) より小さい正の値の 2 つのキーについて特別なことは何もありません。

カウントをチェックすると、次のことがわかります。

Console.WriteLine(dict.Count);                           // 6268
Console.WriteLine(dict.Keys.Count());                    // 6268
Console.WriteLine(dict.Keys.Count(dict.Keys.Contains));  // 6266 

これは、.NET4.5 CLR で実行されるシングル スレッドの .NET4 コードです。辞書はバニラです。Dictionary<uint, float>つまり、カスタムの等値比較器はありません。uint/int の違いが原因でハッシュの問題が発生していると思いContainsKey(key)ますが、ディクショナリの Key コレクションで返されるすべてのキーに対して真であることが保証されるべきではありませんか? 特に、下のコード スニペットのように KeyCollection オブジェクトのみを見ると、合計数と含まれるオブジェクトの数がずれており、奇妙ICollectionな動作のように感じられます。

編集:

予想どおり、合理的な説明があるようです。コレクション、初期化中に 2 つの同時スレッドによって以前に変更されました。何かが「時々壊れる」場合、それはスレッドの問題であり、確かに。複数のスレッドから dict にアクセスすると、明らかに内部状態が混乱して、残りの存続期間は半機能状態になる可能性がありますが、例外は発生しません。

並行辞書に切り替えて、おそらくこの質問を削除します。ありがとう。

4

4 に答える 4

1

GetDictionary()が辞書を作成するときに、カスタムキー等価比較器を追加する可能性はありますか?その場合、問題はコンパレータの実装に関連している可能性があります。

于 2013-03-19T21:10:04.753 に答える
1

コメントするのに十分な担当者がいませんが、私はあなたの問題を無駄に再現しようとしました。GetDictionary()がどのように機能しているかを投稿することをお勧めします。また、そのような辞書を反復処理しないことをお勧めします。代わりに以下を実行して、問題が解決するかどうかを確認してください。

foreach (KeyValuePair<uint, float> pair in dict)
    Console.WriteLine("[" + pair.Key + "]=" + pair.Value);
于 2013-03-19T21:04:12.840 に答える
0

重要な注意:GetHashCodeこの記事全体でを参照するときは、 の結果を参照していIEqualityComparer<T>.GetHashCodeます。デフォルトでは、辞書は を使用します。これは、キー自体EqualityComparer<T>.Defaultを呼び出した結果を返します。ただし、ディクショナリの作成時にGetHashCode特定の実装を提供して、別の動作を使用することができます。IEqualityComparer<T>

これはGetHashCode、値がディクショナリに追加されてからキーを列挙した時点までの間にキーの結果が変化した場合に発生する可能性があります。キーを列挙すると、配列に入力されたすべての「バケット」のキーが返されます。ただし、特定のキーを検索すると、キーの結果から予想されるバケットが再計算されGetHashCodeます。ハッシュ コードが変更された場合、ディクショナリのバケット内のキーと値のペアの実際の場所と予想される場所が同じでなくなる可能性があり、その場合Containsは false が返されます。

GetHashCodeキーのディクショナリに値が追加された後、ディクショナリ内のキーの結果が変化しないことを確認する必要があります。

于 2013-03-19T21:16:55.320 に答える
0

System.Uri でも同様の奇妙な動作に遭遇しました。

ディクショナリに保存されているキーと、検索に使用していたキーとの間のアーキテクチャの不一致であることが判明しました。特に、辞書に格納されている Uri は 32 ビットでしたが、64 ビットのものを探していました。明らかに、GetHashcode() は異なるアーキテクチャ間で同等であることが許可されていないため、ディクショナリはキーを一致させることができませんでした。

于 2013-03-19T22:04:29.517 に答える