15

次のような C# の Address クラスがあります。

public class Address
{            
    public string StreetAddress { get; set; }
    public string RuralRoute { get; set; }
    public string City { get; set; }
    public string Province { get; set; }
    public string Country { get; set; }
    public string PostalCode { get; set; }
}

私は平等を実装しているので、ハッシュコードをオーバーライドする必要があります。最初は EJ のハッシュコード式を使用するつもりでしたが、次のように考えました: これらはすべて文字列フィールドです。StringBuilder を使用してそれらを連結し、その文字列からハッシュ コードを返すことはできないのでしょうか?

あれは:

var str = new StringBuilder();
str.Append(StreetAddress)
   .Append(RuralRoute)
   ...

return str.ToString().GetHashCode();

これの利点/欠点は何ですか? なぜ私はそれをすべきではないのですか?

4

4 に答える 4

16

衝突を単純にすることに関するKosi2801のポイントも関連していますが、無意味に一連の文字列を作成するという理由だけでそれを行うことは避けます。(フィールドの性質上、実際には多くの衝突は発生しないと思いますが...)

この回答で以前に使用した「シンプルで簡単に正しくなる」アルゴリズムを使用します(ランスを調べてくれてありがとう:)-そして、あなたが言ったように、効果的なJavaにリストされています。この場合、次のようになります。

public int GetHashCode()
{
    int hash = 17;
    // Suitable nullity checks etc, of course :)
    hash = hash * 23 + StreetAddress.GetHashCode();
    hash = hash * 23 + RuralRoute.GetHashCode();
    hash = hash * 23 + City.GetHashCode();
    hash = hash * 23 + Province.GetHashCode();
    hash = hash * 23 + Country.GetHashCode();
    hash = hash * 23 + PostalCode.GetHashCode();
    return hash;
}

もちろん、それはヌルセーフではありません。C# 3 を使用している場合は、拡張メソッドを検討することをお勧めします。

public static int GetNullSafeHashCode<T>(this T value) where T : class
{
    return value == null ? 1 : value.GetHashCode();
}

次に、次を使用できます。

public int GetHashCode()
{
    int hash = 17;
    // Suitable nullity checks etc, of course :)
    hash = hash * 23 + StreetAddress.GetNullSafeHashCode();
    hash = hash * 23 + RuralRoute.GetNullSafeHashCode();
    hash = hash * 23 + City.GetNullSafeHashCode();
    hash = hash * 23 + Province.GetNullSafeHashCode();
    hash = hash * 23 + Country.GetNullSafeHashCode();
    hash = hash * 23 + PostalCode.GetNullSafeHashCode();
    return hash;
}

これをさらに簡単にするために、パラメーター配列メソッド ユーティリティを作成できます。

public static int GetHashCode(params object[] values)
{
    int hash = 17;
    foreach (object value in values)
    {
        hash = hash * 23 + value.GetNullSafeHashCode();
    }
    return hash;
}

そしてそれを呼び出す:

public int GetHashCode()
{
    return HashHelpers.GetHashCode(StreetAddress, RuralRoute, City,
                                   Province, Country, PostalCode);
}

ほとんどの型にはプリミティブが含まれているため、多少不必要にボクシングが実行されますが、この場合は参照しかありません。もちろん、不必要に配列を作成することになりますが、時期尚早の最適化について彼らが何を言っているか知っています...

于 2009-06-05T19:25:00.277 に答える
5

ハッシュコードは同じでもオブジェクトが異なる可能性があるため、これを行わないでください。

のことを考える

"StreetAddress" + "RuralRoute" + "City"

"Street" + "AddressRural" + "RouteCity"

どちらもハッシュコードは同じですが、フィールドの内容が異なります。

于 2009-06-05T19:16:42.680 に答える
0

この種のことのために、あなたは実装したいと思うかもしれませんIEqualityComparer<Address>:

public class Address : IEqualityComparer<Address>
{        
    //
    // member declarations
    //

    bool IEqualityComparer<Address>.Equals(Address x, Address y)
    {
        // implementation here
    }

    int IEqualityComparer<Address>.GetHashCode(Item obj)
    {
        // implementation here
    }
}

IComparable<Address>注文を取得するために実装することもできます...

于 2009-06-05T19:30:21.607 に答える