web-dev-qa-db-ja.com

オブジェクトの識別子がnullの場合、GetHashCodeは何を返す必要がありますか?

IDプロパティがnullになる可能性があることを考慮すると、次のうち正しい/良いものはどれですか。

public override int GetHashCode()
{
    if (ID == null) {
        return base.GetHashCode();
    }
    return ID.GetHashCode();
}

OR

public override int GetHashCode()
{
    if (ID != null) {
        return ID.GetHashCode();
    }
     return 0;
}

更新1:2番目のオプションを更新しました。

アップデート2:以下はEqualsの実装です。

public bool Equals(IContract other)
{
    if (other == null)
        return false;
    if (this.ID.Equals(other.ID)) {
        return true;
    }
    return false;
}

public override bool Equals(object obj)
{
    if (obj == null)
        return base.Equals(obj);
    if (!obj is IContract) {
        throw new InvalidCastException("The 'obj' argument is not an IContract object.");
    } else {
        return Equals((IContract)obj);
    }
}

また、IDはstringタイプです。

24
Dienekes

平等の意味によって異なります。重要なことは、2つの等しいオブジェクトが同じハッシュコードを返すことです。 IDがnullの場合、平等とはどういう意味ですか?現在、Equalsメソッドはhave IDプロパティが同じ値の場合にtrueを返します...しかし、IDがnullの場合はどうなるかわかりません。

あなたが実際に欲しい最初のバージョンの振る舞いなら、私は個人的に以下を使用します:

_return ID == null ? base.GetHashCode() : ID.GetHashCode();
_

編集:Equalsメソッドに基づくと、GetHashCodeメソッドを作成できるようです。

_return ID == null ? 0 : ID.GetHashCode();
_

Equals(IContract other)メソッドも次のようになることに注意してください。

_return other != null && object.Equals(this.ID, other.ID);
_

_this.ID_がnullの場合、現在の実装は実際に例外をスローします。

さらに、Equals(object)メソッドが正しくありません。不適切なオブジェクトタイプが渡された場合に例外をスローしないでください。falseがnullの場合は、obj...と同じように返す必要があります。したがって、実際には次のものを使用できます。

_public override bool Equals(object obj)
{
    return Equals(obj as IContract);
}
_

しかし、私はインターフェースに基づく平等が心配です。通常、異なるタイプの2つのクラスは、同じインターフェースを実装している場合でも、等しいと見なされるべきではありません。

25
Jon Skeet

単純にreturn 0;できます。同じ値に対して同じハッシュコードを返す必要があり、ID.GetHashCode()によって0が返されることはあまりないため、このようなハッシュ関数はあらゆるニーズに対応できます。値(IDや名前ハッシュなど)を組み合わせていないため、そのかなり明確なIDがHashCodeの定義ソースであるため、NullIDの0を修正するのが妥当と思われます。

そうでなければ、IDフィールドのみを考慮したGetHashCodeオーバーライドのアプローチ全体が間違っている可能性があります(そして、それらからハッシュを計算するには、いくつかのフィールドを組み合わせる必要があります)

編集後、2番目のEqualsオーバーライドのコードが多すぎると言えます。単に、次のように置き換えてください。

public override bool Equals(object obj)
{
    return Equals(obj as Contract);
}

あなたのEquals(IContract契約)オーバーライドは私にはバグがあるように見えます。契約を定義するのはIDだけであり、IContractにIDよりも多くのフィールドがある場合、それは悪いEqualsオーバーライドになります。

PS:実際、IContractがインターフェースである場合、同じインターフェースを実装する異なるクラスのインスタンスが等しいことを返すことができるように設計が悪くなるため、おそらくIEquatable<IContract>を具体的なIEquatable<ClassName>コントラクトに置き換える必要があります。定義上、同等性を引き起こすには、同等性チェックの最初の段階でオブジェクトが同じタイプであることを確認する必要があります(通常は99,9%の場合など)

4
Valentin Kuzub

たぶんあなたが欲しいのはこのようなものですか?

override int GetHashCode()
{
    if (ID != null)
        return ID.GetHashCode();

    return DBNull.Value.GetHashCode();
}

重要なことはこれです、null IDを持つ2つのオブジェクトは等しいと見なされるべきですか?

0
MattDavey