2

さて、私は等式演算子をオーバーライドしたいクラスを持っているので、次のコードがあります:

/// <summary>
/// Over-ride of the equality operator.
/// </summary>
/// <param name="credential1">The left hand object to test for equality.</param>
/// <param name="credential2">The right hand object to test for equality.</param>
/// <returns>True if the objects are equal.</returns>
public static bool operator ==(KnownServerCredential credential1, KnownServerCredential credential2)
{
    // ok check if either is null
    bool cell1Null = Equals(null, credential1);
    bool cell2Null = Equals(null, credential2);

    // if both are, then it's true
    if (cell1Null && cell2Null)
    {
        return true;
    }

    // if only one is, then how can they be the same?
    if (cell1Null || cell2Null)
    {
        return false;
    }

    // neither are - so we can now go to full on equality
    return credential1.IsEqualTo(credential2);
}

これは問題なく動作し、私はそれに満足しています。ただし、静的分析ツール(ResharperとVS2010コード分析の両方)は、上の2行でnullをチェックしている方法のために、最後の行がnull参照例外をスローする可能性があることを盲目的に誓います。上の2行をからに変更するEquals(null, credentialX)credentialX == null、静的分析ツールは問題ありませんが、等価オーバーライドを再帰的に呼び出しているため、スタックオーバーフローの例外が発生します。を使用することで両方の長所を活かすことができますが、(object)credentialX == nullそれが最もクリーンな方法ではないようです。

簡単な質問は、何かが足りないのか、それとも私が探しているものを達成するための最良の方法をキャストアンドコンペアするのかということです。

4

2 に答える 2

3

オブジェクトのペアが等しいかどうかを確認するには、参照の等価性と構造/値の等価性の 2 つの方法があります。参照の等価性はすべての参照型 (クラス) のデフォルトであり、構造の等価性はすべての値型のデフォルトです (ただし、デフォルトの実装は最適ではありません)。次のガイドを使用して、参照型と値型の両方に構造的等価性を実装します。

平等

等価チェックは、次の規則に従う必要があります。

  • オブジェクトはそれ自体と等しい (同一性)
  • との比較は、との比較と同じ真実xを返します。(対称)yyx
  • xが に等しくy、が に等しい場合、yは に等しくなければなりません。(推移性)zxz
  • オブジェクトが と等しくなることはありませんnull
  • nullに等しいnullです。
  • 例外はスローされません。

クラスまたは構造体IEquatable<T>にカスタム等値チェック用のインターフェイスを実装させてから、 メソッドIEquatable<T>.Equals(T)Object.Equals()メソッドを実装します。

参照型 (クラス) の等価性

IEquatable<T>.Equals(T)参照型の場合、次のようにメソッドを実装します。

public bool Equals(MyType other)
{
    if (Object.ReferenceEquals(other, null) ||      // When 'other' is null
        other.GetType() != this.GetType())          // or of a different type
        return false;                               // they are not equal.
    return this.field1 == other.field1
        && this.field2 == other.field2;
}

Object.Equals()次に、次のようにオーバーライドします。

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

値型 (構造体) の等価性

値の型を にすることはできないため、次のようにメソッドnullを実装します。IEquatable<T>.Equals(T)

public bool Equals(MyType other)
{
    return this.field == other.field
        && this.field2 == other.field2;
}

Object.Equals()次に、次のようにオーバーライドします。

public override bool Equals(object obj)
{
    if (!(obj is MyType))
        return false;
    return Equals((MyType)obj);
}

等値演算子

参照型と値型の両方について、デフォルトの等値演算子と不等値演算子をオーバーライドしたい場合があります。Jon Skeet によるこの投稿に基づいて、等値演算子と不等値演算子は次のように実装できます。

public static bool operator ==(MyType left, MyType right)
{
    return Object.Equals(left, right);
}

public static bool operator !=(MyType left, MyType right)
{
    return !(left == right);
}

leftand/or rightisnullの場合は、オーバーライドObject.Equals(object, object)を呼び出さない(したがって、メソッドを呼び出さない)ことに注意してください。Object.Equals(object)IEquatable<T>.Equals(T)

ハッシュコード

オブジェクトがディクショナリまたはハッシュ テーブルに配置される場合など、オブジェクトのハッシュ コードが重要な場合があります。一般に、Equals()メソッドをオーバーライドするときは、メソッドをオーバーライドしますGetHashCode()。ハッシュ コードは次の規則に従う必要があります。

  • オブジェクト内のいくつかのフィールドを変更した後でも、ハッシュ コードは決して変更しないでください。
  • 等しいと見なされるオブジェクトの場合、ハッシュ コードは等しい必要があります。
  • ハッシュ コードは、等しくないと見なされるオブジェクトの任意のもの (等しいものを含む) である可能性があります。
  • ハッシュ コードはランダムに配布する必要があります。
  • ハッシュ コード関数は例外をスローしてはならず、常に返さなければなりません。
  • ハッシュ コードは非常に高速に計算する必要があります。

したがって、Object.GetHashCode()構造的等価性を使用するクラスまたは構造体を実装するには、オブジェクトから不変のフィールドをいくつか選択し、それらをマークしますreadonly。これらのフィールドのみを使用して、ハッシュ コードを計算します。Object.GetHashCode()メソッドをオーバーライドして、次のように実装します

public override int GetHashCode()
{
    unchecked
    {
        int hash = 17;
        // Don't forget to check for null values.
        hash = hash * 29 + field1.GetHashCode();
        hash = hash * 29 + field2.GetHashCode();
        // ...
        return hash;
    }
}

または、不変フィールドが 1 つしかない場合は、次のものを使用することを検討できます。

public override int GetHashCode()
{
    // Don't forget to check for null values.
    return field1.GetHashCode();
}

不変フィールドがない場合は、定数ハッシュ コードを返します。たとえば、型自体のハッシュ コードです

public override int GetHashCode()
{
    return GetType().GetHashCode();
}

コレクションの構造的等価性

Equals()デフォルトの方法を使用してコレクションを比較しないでください。代わりに、コレクションのデフォルトの等価性は参照等価性にする必要があります。構造的等価性も実装するには、IStructuralEquatableインターフェイスを実装します。例えば:

bool IStructuralEquatable.Equals(object obj, IEqualityComparer comparer)
{
    var other = obj as MyType;
    if (other == null)
        return false;
    return ((IStructuralEquatable)this.innerArray)
        .Equals(other.innerArray, comparer);
}

int IStructuralEquatable.GetHashCode(IEqualityComparer comparer)
{
    return ((IStructuralEquatable)this.innerArray).GetHashCode(comparer);
}
于 2012-07-19T11:28:47.920 に答える
2

通常、null と等しいかどうかを確認する必要がある場合は、次を使用します。

if (object.ReferenceEquals(myref, null))
{

Equalsオーバーロードされたandをバイパスするという利点がありoperator==ます。

于 2012-07-19T11:26:24.143 に答える