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

时间:2022-07-10 19:10:23

For a reference type (class) like Point3 (for example), is this an overkill, lacking:

对于像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 );
}

Please make adjustments or post a new one for both value and reference types, that I can use in my base types (value and reference) without thinking too much every time I implement it again.

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

EDIT: This is for immutable types.

编辑:这是不可变类型。

4 个解决方案

#1


Well, first of all, don't fall into the trap of producing a hash code using XOR as your combination operator.

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

Otherwise, you'll have the following problems, where HC(x) means "the hash code of object/value x":

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

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

Instead, opt for something that at least takes the order of the values into account, like the following:

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

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

This will preserver ordering, as much as possible.

这将尽可能地保留订购。

#2


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

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

That will be slow. Use obj is Type rather.

那将是缓慢的。使用obj是Type而不是。

ReferenceEquals is pointless for valuetypes, which I assume Point3 is.

ReferenceEquals对于valuetypes是没有意义的,我假设Point3是。

I would also not bother with the hash code check in equality procedures.

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

#3


If you are really into performance and your values x, y and z do not change (at least very often), while you do a lot of comparisons, you could pre-calculate your hashcode. Then use it very early during your equality-comparison.

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

But the best in this case is: use a profiler to find the real bottleneck.

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

#4


ALso, if you are creating your own Equals method, you should think about implementing IEquatable. This gives you a nice equality method to compare the same type, and often you can cut down the Equals(object) method to (for reference types):

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

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

As well as being a bit nicer, this cuts down a box operation if the type is a struct - provided the IEquatable implementation is implicit, code will automatically use the typed Equals(Point3) method, rather than using Equals(object) that involves a box operation (and presumably an unbox actually inside that method)

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

#1


Well, first of all, don't fall into the trap of producing a hash code using XOR as your combination operator.

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

Otherwise, you'll have the following problems, where HC(x) means "the hash code of object/value x":

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

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

Instead, opt for something that at least takes the order of the values into account, like the following:

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

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

This will preserver ordering, as much as possible.

这将尽可能地保留订购。

#2


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

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

That will be slow. Use obj is Type rather.

那将是缓慢的。使用obj是Type而不是。

ReferenceEquals is pointless for valuetypes, which I assume Point3 is.

ReferenceEquals对于valuetypes是没有意义的,我假设Point3是。

I would also not bother with the hash code check in equality procedures.

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

#3


If you are really into performance and your values x, y and z do not change (at least very often), while you do a lot of comparisons, you could pre-calculate your hashcode. Then use it very early during your equality-comparison.

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

But the best in this case is: use a profiler to find the real bottleneck.

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

#4


ALso, if you are creating your own Equals method, you should think about implementing IEquatable. This gives you a nice equality method to compare the same type, and often you can cut down the Equals(object) method to (for reference types):

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

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

As well as being a bit nicer, this cuts down a box operation if the type is a struct - provided the IEquatable implementation is implicit, code will automatically use the typed Equals(Point3) method, rather than using Equals(object) that involves a box operation (and presumably an unbox actually inside that method)

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