3

これを正しく行うのにいくつか問題があったので、これがカスタム不変クラスのEqualsメソッドと等式/不等式演算子を実装する効率的な方法であるかどうかについてフィードバックがあるかどうかを尋ねたいと思いました。これらの演算子は私のプログラムによって非常に頻繁に呼び出されるので、正しく取得できるようにしたいと思います。

class MyObj
{

    public static bool operator ==(MyObj a, MyObj b)
    {
        if (!object.ReferenceEquals(a, null))
            return a.Equals(b);
        else if (!object.ReferenceEquals(b, null))
            return b.Equals(a);
        else
            // both are null
            return true;
    }

    public static bool operator !=(MyObj a, MyObj b)
    {
        if (!object.ReferenceEquals(a, null))
            return !a.Equals(b);
        else if (!object.ReferenceEquals(b, null))
            return !b.Equals(a);
        else
            // both are null
            return false
    }

    public override bool Equals(object obj)
    {
        return this.Equals(obj as MyObj);
    }

    public bool Equals(MyObj obj)
    {
        if (object.ReferenceEquals(obj, null))
            return false;
        else
            return (obj.FieldOne == this.FieldOne &&
                    obj.FieldTwo == this.FieldTwo && ...);
    }

}
4

5 に答える 5

2

私の意見では、参照型には次のコードスニペットを使用します。これは、重複が少なく、よりクリーンに感じられます。静的な「Equals」メソッドを使用すると、演算子のオーバーロードなしで.NET言語を使用して、インスタンスメソッドを呼び出す前にnullをテストしなくてもインスタンスを比較できます。等式演算子を実装している場合は、可能であれば、クラスを不変にすることも最適です。

class Foo : IEquatable<Foo>
{
    public override bool Equals(object obj)
    {
        return Equals(obj as Foo);
    }

    public bool Equals(Foo other)
    {
        if (object.ReferenceEquals(other, null)) return false;

        // Optional early out
        if (object.ReferenceEquals(this, other)) return true; 

        // Compare fields here
    }

    public static bool Equals(Foo a, Foo b)
    {
        if (ReferenceEquals(a, null)) return ReferenceEquals(b, null);
        return a.Equals(b);
    }

    public static bool operator ==(Foo a, Foo b)
    {
        return Equals(a, b);
    }

    public static bool operator !=(Foo a, Foo b)
    {
        return !Equals(a, b);
    }
}
于 2009-10-31T16:20:31.543 に答える
2

私が気づいているいくつかのこと:

  • をオーバーライドしているためEquals、 もオーバーライドする必要がありますGetHashCode
  • メソッドはインターフェイスEquals(MyObj)全体の有効な実装であるため、実際にそのインターフェイスを実装する必要があります。これにより、 などを経由する代わりに、メソッドを直接利用することもできます。IEquatable<MyObj>MyObjDictionary<>Equals(MyObj)Equals(object)

また、 の代わりにa != bas を直接実装することを除いて、Trillian の代替実装に完全に同意します。(もちろん些細な違いです。)!(a == b)!Equals(a, b)

于 2009-10-31T16:26:12.520 に答える
0

基本的には可能ですが、修正するエラーがあります。

メソッドは、メソッドEquals(object)を呼び出す代わりにそれ自体を呼び出しEquals(MyObj)、永遠のループを引き起こします。そのはず:

public override bool Equals(object obj) {
   MyObj other = obj as MyObj;
   return this.Equals(other);
}

または単に:

public override bool Equals(object obj) {
   return this.Equals(obj as MyObj);
}

また、不等式演算子を次のように簡略化できます。

public static bool operator !=(MyObj a, MyObj b) {
   return !(a == b);
}
于 2009-10-31T16:23:43.507 に答える
0

効率を求める場合は、次の代わりにこれを使用することをお勧めしますobject.ReferenceEquals(foo, null)

(object)foo == null

これは事実上同等ですが、関数呼び出しを回避します。

IEquatable<T>また、オーバーライドするすべての型に実装するのも好きEqualsです。参照型については、次に転送Equals(object)Equals(Foo)ます。

public override bool Equals(object other){return Equals(other as Foo);}

演算子のオーバーロードは、次のように単純化できます。

public static bool operator==(Foo a, Foo b){
    if((object)a == null)
        return (object)b == null;
    return a.Equals(b);
}
public static bool operator!=(Foo a, Foo b){
    return !(a == b);
}

ただし、絶対的な効率が必要な場合は、余分な関数呼び出しを避けるためにこれらの関数のコードを少し複製する価値があるかもしれませんが、(object)foo == null代わりに を使用するのとは異なりobject.ReferenceEquals(foo, null)、関数呼び出しを避けるには維持するために余分なコードが必要になるため、小さな利益は得られない可能性があります。価値がある。

于 2009-10-31T16:32:55.573 に答える
0

「これがnullの場合は、それ以外の場合...」のすべてのロジックをフレームワークに残すことを好みます。

class MyObj : IEquatable<MyObj> {

  public static bool operator ==( MyObj left, MyObj right ) {
    return EqualityComparer<MyObj>.Default.Equals( left, right );
  }

  public static bool operator !=( MyObj left, MyObj right ) {
    return !EqualityComparer<MyObj>.Default.Equals( left, right );
  }

  public override bool Equals( object obj ) {
    return this.Equals( obj as MyObj );
  }

  public bool Equals( MyObj other ) {
    return !object.ReferenceEquals( other, null )
        && obj.FieldOne == this.FieldOne
        && obj.FieldTwo == this.FieldTwo
        && ...
        ;
  }

  ...

}

オーバーライドされた GetHashCode に最適なアルゴリズムは何ですか?も参照してください。実装するためGetHashCode

于 2010-10-09T16:03:40.797 に答える