分别对值和引用类型进行最完整的Equals实现

时间:2009-05-30 20:03:28

标签: c# .net equals

对于像Point3这样的引用类型(类)(例如),这是一种过度杀伤,缺乏:

#region System.Object Members

public override bool Equals ( object obj )
{
        //return this == ( Point3 ) obj;

        if ( obj == null )
        {
                return false;
        }

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

        return this.Equals ( ( Point3 ) obj );
}

public override int GetHashCode ( )
{
        return this.X.GetHashCode ( ) ^ this.Y.GetHashCode ( ) ^ this.Z.GetHashCode ( );
}

public override string ToString ( )
{
        return String.Format ( "[{0}, {1}, {2}]", this.X, this.Y, this.Z );
}

#endregion

#region IEquatable<Point3> Members

public bool Equals ( Point3 other )
{
        if ( other == null )
        {
                return false;
        }

        if ( ReferenceEquals ( this, other ) )
        {
                return true;
        }

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

        if ( !base.Equals ( other ) )
        {
                return false;
        }

        return this == other;
}

#endregion

public static bool operator == ( Point3 v0, Point3 v1 )
{
        return ( v0.X.IsEqual ( v1.X ) ) && ( v0.Y.IsEqual ( v1.Y ) ) && ( v0.Z.IsEqual ( v1.Z ) );
}

public static bool operator != ( Point3 v0, Point3 v1 )
{
        return !( v0 == v1 );
}

请为我的基本类型(值和参考)中的值和引用类型进行调整或发布一个新的值,而不必在每次重新实现时都考虑太多。

编辑:这是针对不可变类型的。

4 个答案:

答案 0 :(得分:4)

首先,不要陷入使用XOR作为组合运算符生成哈希码的陷阱。

否则,您将遇到以下问题,其中HC(x)表示“对象/值x的哈希码”:

HC(a,b) = HC(b,a)
HC(a,a) = HC(b,b) = 0

相反,选择至少考虑值的顺序的内容,如下所示:

hashcode = 23 // prime number
for each sub-value of the object, do:
    hashcode = hashcode * 31 // another prime number
    hashcode = hashcode + the hashcode of the sub-value

这将尽可能地保留订购。

答案 1 :(得分:3)

  

this.GetType()!= obj.GetType()

那会很慢。请使用obj is Type

ReferenceEquals对于值类型是没有意义的,我假设Point3是。

我也不会在等式过程中使用哈希码检查。

答案 2 :(得分:2)

如果你真的进入了性能并且你的值x,y和z没有改变(至少经常),当你进行大量的比较时,你可以预先计算你的哈希码。然后在你的平等比较中尽早使用它。

但在这种情况下最好的是:使用分析器找到真正的瓶颈。

答案 3 :(得分:2)

另外,如果你要创建自己的Equals方法,你应该考虑实现IEquatable。这为您提供了一个比较相同类型的好的相等方法,通常可以将Equals(object)方法减少为(对于引用类型):

public override Equals(object other)
{
    Point3 otherP = other as Point3;
    return otherP != null && Equals(otherP); // calls the Equals(Point3) method
}

除了更好一点之外,如果类型是结构,这会减少一个盒子操作 - 如果IEquatable实现是隐式的,代码将自动使用类型化的Equals(Point3)方法,而不是使用Equals(object)这涉及一个盒子操作(实际上可能是在该方法中的unbox)