System.String オブジェクトがハッシュ コードをキャッシュしないのはなぜでしょうか? 質問する

System.String オブジェクトがハッシュ コードをキャッシュしないのはなぜでしょうか? 質問する

ソースコードを見てみるとstring.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 の形式で実装されますか?」という質問には、実際には答えられません。私はいくつかの点について興味があります。

  1. リフレクターがDLLを正しく逆アセンブルし、これがの実装(私の環境)では、この特定の実装に基づくオブジェクトはハッシュ コードをキャッシュしないGetHashCodeことを示すようにこのコードを解釈するのは正しいでしょうか?string
  2. 答えが「はい」だと仮定すると、これはなぜでしょうか。メモリ コストは最小限 (32 ビット整数が 1 つ増えるだけで、文字列自体のサイズに比べればほんのわずか) である一方、節約できる量は大きく、特に、たとえば のようなハッシュテーブル ベースのコレクションで文字列がキーとして使用される場合に顕著になると思われますDictionary<string, [...]>。また、クラスは不変であるためstring、 によって返される値がGetHashCode変わることもありません。

何が欠けているのでしょうか?


アップデートアンドラーシュ・ゾルタン氏の閉会の挨拶に応えて:

Tim の回答 (+1) にも指摘されている点があります。彼が正しいとすれば (私はそう思います)、文字列が構築後に実際に不変であるという保証はないので、結果をキャッシュするのは間違いです。

うわあ、うわあそこに!これは興味深い指摘です(そしてはい、それは本当です)、 しかし、私本当に疑うの実装ではこれが考慮されていましたGetHashCode。「したがって、結果をキャッシュするのは間違っている」という文は、文字列に関するフレームワークの態度が「まあ、それらは察するに不変ですが、開発者がこっそりやりたい場合は変更可能なので、そのように扱います。」これはフレームワークが文字列をどのように見ているかではありませんは、さまざまな方法 (文字列リテラルのインターン、長さがゼロのすべての文字列の への割り当てstring.Emptyなど) でその不変性に完全に依存しているため、基本的に、文字列を変更すると、動作が完全に未定義で予測不可能なコードを記述することになります。

私が言いたいのは、この実装の作成者が「公開されているクラスは不変であるにもかかわらず、この文字列インスタンスが呼び出し間で変更されたらどうなるか」と心配するのは、カジュアルな屋外バーベキューを計画している人が「誰かがパーティーに原子爆弾を持ってきたらどうなるか」と考えるのと同じだということです。ほら、誰かが原子爆弾を持ってきたら、パーティーは終わりです。

ベストアンサー1

明らかな答えは、メモリを消費するからです。

ここに費用対効果分析があります:

料金: 文字列ごとに4バイト(GetHashCodeの各呼び出しで簡単なテスト)。また、文字列オブジェクトを可変にすると、実装に注意する必要があることは明らかです。いつもハッシュコードを事前に計算する。これは、一度計算するコストである。ハッシュするかどうかに関係なく、文字列になります。

利点: ハッシュの再計算を避ける複数回ハッシュされた文字列値の場合

多くの場合、文字列オブジェクトは非常に多く、そのうちハッシュされるのはごくわずかであるため、純粋なコストは高くなると考えられます。ただし、明らかにそうではない場合もあります。

どちらがより頻繁に発生するかを判断する立場にはないと思います... MSがさまざまな実際のアプリを実装してくれることを期待します。(また、SunがJavaに対して同じことをしてくれることを期待します。するハッシュをキャッシュします...)

編集:私はちょうどこのことについてエリック・リッパートと話しました(NDCは素晴らしいです:)そして基本的にはメモリ使用量の増加と限られたメリットについて。

おすすめ記事