2

假设我有一个 Point2 类,我想实现以下 Equals:

public override bool Equals ( object obj )

public bool Equals ( Point2 obj )

这是来自有效的 C# 3 书:

public override bool Equals ( object obj )
{
    // STEP 1: Check for null
    if ( obj == null )
    {
        return false;
    }

    // STEP 3: equivalent data types
    if ( this.GetType ( ) != obj.GetType ( ) )
    {
        return false;
    }
    return Equals ( ( Point2 ) obj );
}

public bool Equals ( Point2 obj )
{
    // STEP 1: Check for null if nullable (e.g., a reference type)
    if ( obj == null )
    {
        return false;
    }
    // STEP 2: Check for ReferenceEquals if this is a reference type
    if ( ReferenceEquals ( this, obj ) )
    {
        return true;
    }
    // STEP 4: Possibly check for equivalent hash codes
    if ( this.GetHashCode ( ) != obj.GetHashCode ( ) )
    {
        return false;
    }
    // STEP 5: Check base.Equals if base overrides Equals()
    System.Diagnostics.Debug.Assert (
        base.GetType ( ) != typeof ( object ) );

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

    // STEP 6: Compare identifying fields for equality.
    return ( ( this.X.Equals ( obj.X ) ) && ( this.Y.Equals ( obj.Y ) ) );
}

这是不是矫枉过正?

4

4 回答 4

3

用继承层次支持相等是很棘手的。你需要弄清楚你的意思。你真的需要在这里继承吗?如果不是 - 如果 Point2 直接从 System.Object 派生,并且您可以将其密封,生活会变得更容易一些。在这种情况下,我会使用:

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

public bool Equals (Point2 obj)
{
    // STEP 1: Check for null if nullable (e.g., a reference type)
    // Note use of ReferenceEquals in case you overload ==.
    if (object.ReferenceEquals(obj, null))
    {
        return false;
    }

    // STEP 2: Check for ReferenceEquals if this is a reference type
    // Skip this or not? With only two fields to check, it's probably
    // not worth it. If the later checks are costly, it could be.
    if (object.ReferenceEquals( this, obj))
    {
        return true;
    }

    // STEP 4: Possibly check for equivalent hash codes
    // Skipped in this case: would be *less* efficient

    // STEP 5: Check base.Equals if base overrides Equals()
    // Skipped in this case

    // STEP 6: Compare identifying fields for equality.
    // In this case I'm using == instead of Equals for brevity
    // - assuming X and Y are of a type which overloads ==.
    return this.X == obj.X && this.Y == obj.Y;
}
于 2009-02-20T17:45:27.733 回答
2

不是真的-您几乎考虑了所有可能性。如果此代码用于临时应用程序以外的任何内容,您应该考虑这种方法的好处,因为由于奇怪的对象相等行为导致的逻辑错误很难调试。

于 2009-02-20T17:45:03.053 回答
1

在我看来,这正是你想要的。整个块归结为:

“如果是完全相同的实例,则返回 true。如果它们是具有相同 X 和 Y 值的单独实例,则返回 true。所有其他情况(null、不同类型、不同 x/y 值)返回 false。”

于 2009-02-20T17:44:44.070 回答
1

它肯定比我想为 equals 方法编写的代码多。有很多冗余检查,例如检查 ReferenceEquals 和 HashCodes(我知道这些检查是多余的,因为函数中的最后一行检查结构相等性)。专注于简单易读的代码。

public bool Equals(object o)
{
    Point2 p = o as Point2;
    if (o != null)
        return this.X == o.X && this.Y == o.Y;
    else
        return false;
}

由于您的 equals 方法使用结构相等,因此请确保使用基于您的字段的实现来覆盖 GetHashCode。

于 2009-02-20T17:45:20.683 回答