[解決済み] .NETでは、NULLのハッシュコードは常に0であるべきです。
質問
のようなコレクションがあるとして
System.Collections.Generic.HashSet<>
を受け入れる
null
をセットメンバとすると
null
のハッシュコードがどうあるべきかを問うことができます。フレームワークでは
0
:
// nullable struct type
int? i = null;
i.GetHashCode(); // gives 0
EqualityComparer<int?>.Default.GetHashCode(i); // gives 0
// class type
CultureInfo c = null;
EqualityComparer<CultureInfo>.Default.GetHashCode(c); // gives 0
これは、nullableな列挙型で(少し)問題になることがあります。もし私たちが
enum Season
{
Spring,
Summer,
Autumn,
Winter,
}
とすると
Nullable<Season>
(とも呼ばれる)。
Season?
) は5つの値だけを取ることができますが、そのうちの2つ、つまり
null
と
Season.Spring
は同じハッシュコードを持っています。
このようなquot;better"等値比較器を書きたくなりますね。
class NewNullEnumEqComp<T> : EqualityComparer<T?> where T : struct
{
public override bool Equals(T? x, T? y)
{
return Default.Equals(x, y);
}
public override int GetHashCode(T? x)
{
return x.HasValue ? Default.GetHashCode(x) : -1;
}
}
のハッシュ・コードは、このような場合にも利用できるのでしょうか?
null
は
0
?
編集・追加です。
一部の人々は、これが
Object.GetHashCode()
. 実はそうではありません。(但し、.NET の作者は
GetHashCode()
の中に
Nullable<>
という構造体で
は
に関連するものですが)。ユーザが書いた実装で、パラメータなしの
GetHashCode()
は、求めるハッシュコードを持つオブジェクトが
null
.
これは、抽象的なメソッドである
EqualityComparer<T>.GetHashCode(T)
を実装するか、あるいはインターフェイスメソッド
IEqualityComparer<T>.GetHashCode(T)
. さて、MSDN へのこれらのリンクを作成する際に、これらのメソッドが
ArgumentNullException
が唯一の引数である場合
null
. これは確かにMSDNの間違いに違いない?.NET自身の実装のどれもが例外を投げません。その場合に投げることは、事実上
null
に
HashSet<>
. ただし
HashSet<>
を処理するときに何か特別なことをするのであれば
null
アイテムを扱うときに何か特別なことをします (テストする必要があります)。
新しい編集/追加です。
今度はデバッグをやってみました。とは
HashSet<>
で、デフォルトの等比級数比較器では、値
Season.Spring
と
null
意志
は同じバケツで終わります。このことは、プライベート配列のメンバである
m_buckets
と
m_slots
. インデックスは設計上、常に1つずつオフセットされていることに注意してください。
しかし、私が上であげたコードはこれを修正するものではありません。結論から言うと
HashSet<>
は等価比較器に対して、値が
null
. これは、ソースコードにある
HashSet<>
:
// Workaround Comparers that throw ArgumentNullException for GetHashCode(null).
private int InternalGetHashCode(T item) {
if (item == null) {
return 0;
}
return m_comparer.GetHashCode(item) & Lower31BitMask;
}
ということになります。
については少なくとも
HashSet<>
のハッシュを変更することはできない、ということです。
null
.
代わりに、解決策としては、以下のように他のすべての値のハッシュを変更することです。
class NewerNullEnumEqComp<T> : EqualityComparer<T?> where T : struct
{
public override bool Equals(T? x, T? y)
{
return Default.Equals(x, y);
}
public override int GetHashCode(T? x)
{
return x.HasValue ? 1 + Default.GetHashCode(x) : /* not seen by HashSet: */ 0;
}
}
どのように解決するのですか?
ヌルに対して返されるハッシュコードが 一貫して である限り、問題ないでしょう。ハッシュ コードの唯一の要件は、等しいと考えられる 2 つのオブジェクトが同じハッシュ コードを共有することです。
nullに対して0または-1を返すことで、1つを選んで常にそれを返す限り、動作します。明らかに、非NULLのハッシュコードは、NULLに使用するいかなる値も返してはいけません。
オブジェクトの識別子がNULLの場合、GetHashCodeは何を返すべきですか?
この記事の内容
MSDN のエントリ
は、ハッシュ コードについてより詳細に説明しています。興味深いことに、このドキュメントでは NULL 値について何の説明も議論もありません。
まったく
- コミュニティーのコンテンツにおいてさえもです。
enum に関するあなたの問題に対処するために、ゼロ以外を返すようにハッシュコードを再実装するか、null と同等のデフォルトの "unknown" enum エントリを追加するか、単に null 可能な enum を使用しないようにします。
ところで、興味深い発見がありました。
私が一般的に見るもうひとつの問題は、ハッシュコード ができないことです。 がなければ null にできる 4 バイト以上の型を表すことができないことです。 少なくとも1つの衝突 (型サイズが大きくなるともっと)。例えば、intのハッシュコードはintだけなので、intの全範囲を使用します。その範囲の中でnullにどのような値を選ぶのでしょうか?どんなものを選んでも、値のハッシュコードそのものと衝突してしまいます。
衝突それ自体は必ずしも問題ではありませんが、それがあることを知っておく必要があります。ハッシュ コードは、ある状況でのみ使用されます。MSDN のドキュメントに記載されているように、ハッシュ コードは異なるオブジェクトに対して異なる値を返すことは保証されていないので、期待しないほうがよいでしょう。
関連
-
[解決済み】「未割り当てのローカル変数を使用」とはどういう意味ですか?
-
[解決済み] usingディレクティブはネームスペースの内側と外側のどちらを使うべきですか?
-
[解決済み] JavaScriptのnullとundefinedの違いは何ですか?
-
[解決済み] Pythonでnullオブジェクトを参照する
-
[解決済み] .NETコンソールアプリケーションでアプリケーションのパスを取得するにはどうすればよいですか?
-
[解決済み] .NET Coreと.NET Standard Class Libraryのプロジェクトタイプの違いは何ですか?
-
[解決済み] nullはなぜオブジェクトなのか、nullとundefinedの違いは何ですか?
-
[解決済み] コードが含まれるアセンブリのパスを取得するにはどうすればよいですか?
-
[解決済み] Distinct() with lambda?
-
[解決済み】Nullable型をジェネリックパラメータにすることは可能か?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】GDI+、JPEG画像をMemoryStreamに変換する際にジェネリックエラーが発生しました。
-
[解決済み】Ajax処理で「無効なJSONプリミティブ」と表示される件
-
[解決済み] [Entity Framework 4.1でエンティティに関連オブジェクトを追加する際に、エンティティオブジェクトをIEntityChangeTracker.の複数のインスタンスから参照できない。
-
[解決済み] エンティティタイプ <type> は、現在のコンテキストのモデルの一部ではありません。
-
[解決済み] 'SubSonic.Schema .DatabaseColumn' 型のオブジェクトをシリアライズする際に、循環参照が検出されました。
-
[解決済み】「namespace x already contains a definition for x」エラーの修正方法は?VS2010にコンバートした後に発生しました。
-
[解決済み】非静的メソッドはターゲットを必要とする
-
[解決済み】Moqを使用してメソッド呼び出しを検証する
-
[解決済み】Visual Studio: 操作を完了できませんでした。パラメータが正しくありません
-
[解決済み】 C# 条件演算子エラー 代入、call、increment、decrement、await、new object 式のみ文として使用可能です。