编写等于运算符时处理null的最佳方法

时间:2020-03-05 18:59:50  来源:igfitidea点击:
Possible Duplicate:

  How do I check for nulls in an '==' operator overload without infinite recursion?

当我为对象重载==运算符时,我通常会这样写:

public static bool operator ==(MyObject uq1, MyObject uq2) {
        if (((object)uq1 == null) || ((object)uq2 == null)) return false;
        return uq1.Field1 == uq2.Field1 && uq1.Field2 == uq2.Field2;
    }

如果我们不屈服于对象,那么函数会递归到自身中,但是我想知道是否有更好的方法?

解决方案

回答

ReferenceEquals(对象obj1,对象obj2)

回答

if ((object)uq1 == null) 
    return ((object)uq2 == null)
else if ((object)uq2 == null)
    return false;
else
    //return normal comparison

当两者都为null时,这会将它们比较为相等。

回答

遵循DB处理:

null == <anything> is always false

回答

@ neouser99:这是正确的解决方案,但是遗漏的部分是,当重写相等运算符(运算符==)时,我们还应该重写Equals函数,并简单地使运算符调用该函数。并非所有.NET语言都支持运算符重载,因此,是覆盖Equals函数的原因。

回答

正如微软所说,

A common error in overloads of
  operator == is to use (a == b), (a ==
  null), or (b == null) to check for
  reference equality. This instead
  results in a call to the overloaded
  operator ==, causing an infinite loop.
  Use ReferenceEquals or cast the type
  to Object, to avoid the loop.

因此,使用ReferenceEquals(a,null)|| ReferenceEquals(b,null)是一种可能性,但强制转换为对象也一样(我认为实际上是等效的)。

因此,是的,似乎应该有一种更好的方法,但是建议我们使用一种方法。

但是,正如已经指出的那样,在覆盖==时,我们实际上也应该覆盖Equals。使用LINQ提供程序以不同的语言编写并在运行时进行表达式解析,即使我们自己拥有所有代码,谁也知道不执行该操作的时间。

回答

但是,为什么不创建对象成员函数呢?当然,不能在Null引用上调用它,因此我们确定第一个参数不是Null。

确实,我们失去了二元运算符的对称性,但仍然...

(请注意Purfideas的答案:如果需要作为数组的前哨值,则Null可能等于Null)

还请考虑==函数的语义:有时我们确实希望能够选择是否测试

  • 身份(指向同一对象)
  • 价值平等
  • 等价(例如1.000001等于.9999999)

回答

只需使用Resharper创建Equals和GetHashCode方法。为此,它将创建最全面的代码。

更新
我并不是故意发布它,而是让人们使用Resharper的功能而不是粘贴粘贴,因为代码在每个类之间都不同。关于开发Cwithout Resharper,伙计,我不了解你的生活。

无论如何,这是一个简单类的代码(由Resharper 3.0生成,我正在使用4.0的旧版本,我目前不记得它是否创建相同的代码)

public class Foo : IEquatable<Foo>
{
    public static bool operator !=(Foo foo1, Foo foo2)
    {
        return !Equals(foo1, foo2);
    }

    public static bool operator ==(Foo foo1, Foo foo2)
    {
        return Equals(foo1, foo2);
    }

    public bool Equals(Foo foo)
    {
        if (foo == null) return false;
        return y == foo.y && x == foo.x;
    }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(this, obj)) return true;
        return Equals(obj as Foo);
    }

    public override int GetHashCode()
    {
        return y + 29*x;
    }

    private int y;
    private int x;
}