3

我有一堂课可以实施IEquatable<T>。是否有必要进行参考检查Equals()还是在框架中进行了处理?

class Foo : IEquatable<Foo>
{
    int value;
    Bar system;

    bool Equals(Foo other)
    {
        return this == other || 
        ( value == other.value && system.Equals(other.system) );
    }
}

在上面的例子中,this==other陈述是多余的还是必要的?

更新 1

我知道我需要更正代码如下:

    bool Equals(Foo other)
    {
        if( other==null ) { return false; }
        if( object.ReferenceEquals(this, other) ) { return true; } //avoid recursion
        return value == other.value && system.Equals(other.system);
    }

感谢您的回复。

4

6 回答 6

4

这通常是一种优化——如果Equals没有它,这将是一个奇怪的实现。因此,我不会认为它是必要的——但它也没有“在框架中得到照顾”。我是一个廉价的优化来实现,所以它通常值得包括。

请注意,如果您重载==,那么您可能应该使用object.ReferenceEquals来执行这些比较。

于 2011-01-13T16:31:21.817 回答
4

当心。实际上,我强烈反对这种做法,因为如果您想根据(根据我的经验通常这样做)为您的类型重载==运算符,您会发现自己有无限递归。FooEquals

为了说明我的意思,这里是一个常见的==实现Equals

public static bool operator ==(Foo x, Foo y)
{
    // Will overflow the stack if Equals uses ==:
    return !ReferenceEquals(x, null) && x.Equals(y);
}

也就是说,我完全同意乔恩的观点,即它可能适合使用ReferenceEquals

于 2011-01-13T16:32:25.493 回答
1

从某种意义上说,它可能不是正确性所必需的,但框架肯定不会“照顾它”,所以它可能很有用,通常是出于性能原因。

一点:如果实现由 包装 EqualityComparer<T>.Default,如果一个或两个参数是 ,它不会输入用户代码null,因此在这种情况下它会执行一些引用检查(如果不是完整的ReferenceEquals(x, y))。

public override bool Equals(T x, T y)
{
    if (x != null)
    {
        return ((y != null) && x.Equals(y));
    }
    if (y != null)
    {
        return false;
    }

    return true;
}

题外话,您的示例方法中有几个空解引用问题(other可能是nullthis.system可能是null)。

我会把你的方法写成这样:

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

    if(other == this)
         return true;

    return value == other.value
            && EqualityComparer<Bar>.Default.Equals(bar, other.bar)
            // You don't *have to* go down the EqualityComparer route
            // but you do need to make sure you don't dereference null.

}

GetHashCode还记得在编写自己的相等比较时覆盖。

于 2011-01-13T16:28:59.090 回答
0

我觉得有必要检查一下this == other,因为你自己定义equals。如果您不想对其进行指针检查,请编写自己的IEquatable.

于 2011-01-13T16:28:56.963 回答
0

IEquatable<T>是一个接口;实施取决于实施者。

由于您正在实现接口,因此您应对接口定义的所有预期行为负责。

于 2011-01-13T16:29:23.477 回答
-1

我相信这是必要的。参考检查是您在比较对象时可以执行的第一个快速步骤。

在您给出的示例中,请务必在访问其值之前检查other不为空。

bool Equals(Foo other)
{
    if(other == null) return false;

    if(this == other) return true;

    // Custom comparison logic here.
}
于 2011-01-13T16:30:18.233 回答