Reflectorstring.GetHashCode
を使用するためのソースコードを一目見ると、次のことがわかります(mscorlib.dllバージョン4.0の場合)。
public override unsafe int GetHashCode()
{
fixed (char* str = ((char*) this))
{
char* chPtr = str;
int num = 0x15051505;
int num2 = num;
int* numPtr = (int*) chPtr;
for (int i = this.Length; i > 0; i -= 4)
{
num = (((num << 5) + num) + (num >> 0x1b)) ^ numPtr[0];
if (i <= 2)
{
break;
}
num2 = (((num2 << 5) + num2) + (num2 >> 0x1b)) ^ numPtr[1];
numPtr += 2;
}
return (num + (num2 * 0x5d588b65));
}
}
の実装がGetHashCode
指定されておらず、実装に依存していることに気付いたので、「GetHashCode
XまたはYの形式で実装されていますか?」という質問があります。本当に答えられません。私はいくつかのことに興味があります:
- ReflectorがDLLを正しく分解し、これが
GetHashCode
(私の環境での)実装であるstring
場合、この特定の実装に基づくオブジェクトがハッシュコードをキャッシュしないことを示すために、このコードを解釈するのは正しいですか? - 答えがイエスだとすると、なぜそうなるのでしょうか。メモリコストは最小限であるように思われますが(32ビット整数が1つ増え、文字列自体のサイズと比較して池が低下します)、特に文字列が使用されている場合は、大幅な節約になります。のようなハッシュテーブルベースのコレクションのキーとして
Dictionary<string, [...]>
。また、string
クラスは不変であるため、によって返される値がGetHashCode
変更されることはありません。
何が欠けている可能性がありますか?
更新:Andras Zoltanの閉会の辞に応えて:
ティムの答え(そこに+1)にもポイントがあります。彼が正しい場合、そして私が彼が正しいと思う場合、文字列が構築後に実際に不変であるという保証はありません。したがって、結果をキャッシュすることは間違っています。
おっと、おっ!これは興味深い点です(そしてそうです、それは非常に真実です)が、これがの実装で考慮されたことは本当に疑わしいGetHashCode
です。「したがって、結果をキャッシュするのは間違っている」というステートメントは、文字列に関するフレームワークの態度が「まあ、それらは不変であるはずですが、実際に開発者が卑劣になりたい場合は可変であるため、処理します」ということを意味しますそれら自体。」これは、フレームワークが文字列を表示する方法ではありません。それは非常に多くの方法でそれらの不変性に完全に依存しています(文字列リテラルのインターン、すべての長さゼロの文字列の割り当てstring.Empty
など)、基本的に、文字列を変更すると、動作が完全に定義されておらず、予測できないコードを記述していることになります。
私のポイントは、この実装の作成者が「この文字列インスタンスが、公開されているクラスが不変であるにもかかわらず、呼び出し間で変更された場合はどうなるか」ということです。カジュアルな屋外バーベキューを計画している人が、「誰かが原子爆弾をパーティーに持ってきたらどうなるだろうか」と考えてみてはいかがでしょうか。ほら、誰かが原子爆弾を持ってきたら、パーティーは終わった。