3

C# で正確で柔軟かつ高速な Equalsを実装する最善の方法について考えてみました。パフォーマンスのためには、特殊な Equals (実際のクラスのオブジェクトをパラメーターとして受け取る) が必要であると考えました。コードの重複を避けるために、一般的な Equals は特殊化された Equals を呼び出す必要があります。継承されたクラスであっても、null チェックは 1 回だけ実行する必要があります。

私は最終的にこのデザインを思いつきました:


class MyClass
{
    public Int32 SomeValue1 = 1;
    public Int32 SomeValue2 = 25;

    // Ignoring GetHashCode for simplicity.

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

    public bool Equals(MyClass obj)
    {
        if (obj == null) {
            return false;
        }

        if (!SomeValue1.Equals (obj.SomeValue1)) {
            return false;
        }

        if (!SomeValue2.Equals (obj.SomeValue2)) {
            return false;
        }

        return true;
    }
}

class MyDerivedClass : MyClass
{
    public Int32 YetAnotherValue = 2;

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

    public bool Equals(MyDerivedClass obj)
    {
        if (!base.Equals (obj)) {
            return false;
        }

        if (!YetAnotherValue.Equals (obj.YetAnotherValue)) {
            return false;
        }

        return true;
    }
}

重要なアイデア:

  • 「as」演算子の使用。このようにして、一般的な Equals で null をチェックする必要がなくなります。間違ったクラス タイプは null に縮小され、特殊化された Equals に分類されます。
  • 派生クラスであっても、正確に 1 点で Null チェックを行います。
  • 属性を次々に確認すると、明確な構造が得られます。

この概念に欠陥はありますか、それとも条件を逃しましたか?

4

1 に答える 1

5

異なる型が関係している場合、Equals メソッドは再帰的ではありません。

MyDerivedClass mdc = new MyDerivedClass();
MyClass mc = new MyClass();
Object omdc = mdc;
Object omc = mc;

// mc.Equals(mdc) - true
// mdc.Equals(mc) - true by calling the right overload
// omc.Equals(omdc) - true
// omdc.Equals(omc) - false, the "as" in MyDerivedClass will result in null

これを回避する通常の方法は、次を使用することです。

if (GetType() != other.GetType())
{
    return false;
}

Object.Equalsのドキュメントを参照してください:「x.Equals(y) は y.Equals(x) と同じ値を返します。」異なる結果を得るためにオーバーロードに依存すると、デバッグが非常に微妙な恐ろしい問題が発生する可能性があります。

于 2009-01-20T11:13:29.947 に答える