71

私はC#で構造を持っています:

public struct UserInfo
{
   public string str1
   {
     get;
     set;
   }

   public string str2
   {
     get;
     set;
   }   
}

唯一のルールは、 UserInfo(str1="AA", str2="BB").Equals(UserInfo(str1="BB", str2="AA"))

この構造体の GetHashCode 関数をオーバーライドする方法は?

4

15 に答える 15

70

MSDN :

ハッシュ関数には、次のプロパティが必要です。

  • 2 つのオブジェクトを比較した場合、GetHashCode各オブジェクトのメソッドは同じ値を返す必要があります。ただし、2 つのオブジェクトが等しくない場合、2 つのオブジェクトのGetHashCodeメソッドは異なる値を返す必要はありません。
  • オブジェクトのメソッドGetHashCodeの戻り値を決定するオブジェクトの状態に変更がない限り、オブジェクトのメソッドは一貫して同じハッシュ コードを返す必要がありますEquals。これはアプリケーションの現在の実行にのみ当てはまり、アプリケーションが再度実行されると別のハッシュ コードが返される可能性があることに注意してください。
  • 最高のパフォーマンスを得るには、ハッシュ関数がすべての入力に対してランダムな分布を生成する必要があります。

それを考慮に入れる正しい方法は次のとおりです。

return str1.GetHashCode() ^ str2.GetHashCode() 

^他の可換演算に置き換えることができます

于 2008-09-16T08:32:00.213 に答える
27

Jon Skeet の回答を参照してください^

于 2009-06-22T15:16:58.030 に答える
16
public override int GetHashCode()
{
    unchecked
    {
        return (str1 ?? String.Empty).GetHashCode() +
            (str2 ?? String.Empty).GetHashCode();
    }
}

('AA', 'BB') と ('BB', 'AA') を明示的に同じにしたい場合でも、( 'AA', 'AA') と ('BB', 'BB') が同じであること (または、すべて同じペアであること)。

nullの場合、既知の定数をすぐに返すのではなく、空の文字列に対して「GetHashCode()」を実行するため、このソリューションでは「できるだけ早く」ルールは完全には守られていませんが、明示的に測定しなくても喜んで多くのヌルが予想されない限り、違いが心配するほど大きくないという推測を危険にさらします。

于 2008-09-16T09:33:42.483 に答える
5
  1. 原則として、クラスのハッシュコードを生成する簡単な方法は、ハッシュコードの生成に参加できるすべてのデータフィールドを XOR することです (他の人が指摘したように null を注意深くチェックしてください)。これは、UserInfo("AA", "BB") と UserInfo("BB", "AA") のハッシュコードが同じであるという (人為的な?) 要件も満たしています。

  2. クラスの使用について仮定できる場合は、おそらくハッシュ関数を改善できます。たとえば、str1 と str2 が同じであることが一般的である場合、XOR は適切な選択ではない可能性があります。ただし、str1 と str2 がたとえば姓名を表す場合、XOR はおそらく適切な選択です。

これは明らかに実世界の例を意図したものではありませんが、次のことを指摘する価値はあるかもしれません:ケースはこちら。- セッターでプロパティを使用してハッシュ コードを生成することも問題です。

于 2008-09-16T17:29:15.647 に答える
4

簡単な一般的な方法は、これを行うことです。

return string.Format("{0}/{1}", str1, str2).GetHashCode();

厳密なパフォーマンス要件がない限り、これは私が考えることができる最も簡単な方法であり、複合キーが必要な場合はこの方法を頻繁に使用します。ケースを問題なく処理し、null(m)ハッシュ衝突を(一般に)引き起こしません。文字列に「/」が必要な場合は、予期しない別のセパレータを選択してください。

于 2014-05-08T14:44:37.003 に答える
3
public override int GetHashCode()   
{       
    unchecked      
    {           
        return(str1 != null ? str1.GetHashCode() : 0) ^ (str2 != null ? str2.GetHashCode() : 0);       
    }   
}
于 2008-09-16T09:12:44.467 に答える
2

そうそう、Gary Shutler が指摘したように:

return str1.GetHashCode() + str2.GetHashCode();

オーバーフローする可能性があります。Artem が提案したように long にキャストしてみるか、unchecked キーワードでステートメントを囲むことができます。

return unchecked(str1.GetHashCode() + str2.GetHashCode());
于 2008-09-16T08:33:56.230 に答える
1

これを試してみてください:

(((long)str1.GetHashCode()) + ((long)str2.GetHashCode())).GetHashCode()
于 2008-09-16T08:23:56.613 に答える
0

多くの可能性。例えば

return str1.GetHashCode() ^ str1.GetHashCode()

于 2008-09-16T08:22:27.893 に答える
0

おそらくstr1.GetHashCode()+ str2.GetHashCode()のようなものですか?または(str1.GetHashCode()+ str2.GetHashCode())/ 2?このように、str1とstr2が交換されているかどうかに関係なく同じになります。

于 2008-09-16T08:22:49.423 に答える
0

それらを並べ替えてから、連結します。

return((str1.CompareTo(str2)<1)?str1 + str2:str2 + str1)
    .GetHashCode();
于 2008-09-16T08:27:14.170 に答える
0

GetHashCode の結果は次のようになります。

  1. できるだけ速く。
  2. できるだけユニークに。

それらを念頭に置いて、私は次のようなものに行きます:

if (str1 == null)
    if (str2 == null)
        return 0;
    else
       return str2.GetHashCode();
else
    if (str2 == null)
        return str1.GetHashCode();
    else
       return ((ulong)str1.GetHashCode() | ((ulong)str2.GetHashCode() << 32)).GetHashCode();

編集:ヌルを忘れました。コード修正。

于 2008-09-16T08:31:56.267 に答える
-1

複雑すぎる、null を忘れるなど。これはバケツなどに使用されるため、

if (null != str1) {
    return str1.GetHashCode();
}
if (null != str2) {
    return str2.GetHashCode();
}
//Not sure what you would put here, some constant value will do
return 0;

これは、異常に多くのインスタンスで str1 が一般的である可能性が低いと仮定することによって偏っています。

于 2008-09-16T08:56:48.157 に答える