【问题标题】:Best way to handle null when writing equals operator [duplicate]编写等于运算符时处理 null 的最佳方法 [重复]
【发布时间】:2010-09-10 08:37:18
【问题描述】:

可能重复:
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;
    }

如果你不向下转换为对象,函数会递归到自身,但我想知道是否有更好的方法?

【问题讨论】:

标签: c# operator-overloading equals


【解决方案1】:

ReferenceEquals(对象 obj1, 对象 obj2)

【讨论】:

  • 这似乎并没有真正解决问题 - 例如,ReferenceEquals 不会告诉您一个为空而另一个不是。
  • 为什么人们投票赞成,从我的例子中很明显 ReferenceEquals 不是我想要的
  • 嘿,+4 票和-4 票 :)
  • @GeorgeMauer +1 回答,因为这正是 msdn 推荐的 msdn.microsoft.com/en-us/library/ms173147(VS.80).aspx
【解决方案2】:
if ((object)uq1 == null) 
    return ((object)uq2 == null)
else if ((object)uq2 == null)
    return false;
else
    //return normal comparison

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

【讨论】:

  • 这和我的例子做的一样,只是用更复杂的术语
【解决方案3】:

按照 DB 处理:

null == <anything> is always false

【讨论】:

  • 这并没有解决问题,x == y 如果一个为 null 将递归函数,正如我所说的
【解决方案4】:

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

【讨论】:

  • 真的吗?这很有趣,我一直在做相反的事情
  • 如果您这样做,请确保 == 运算符检查 null。 null == 始终为 null。
【解决方案5】:

正如微软所说,

重载的常见错误 运算符 == 是使用 (a == b), (a == null) 或 (b == null) 来检查 引用相等。这反而 导致调用重载 运算符 ==,导致无限循环。 使用 ReferenceEquals 或强制转换类型 to Object,避免循环。

所以使用 ReferenceEquals(a, null) || ReferenceEquals(b, null) 是一种可能性,但转换为对象同样好(我相信实际上是等价的)。

所以是的,似乎应该有更好的方法,但您使用的方法是推荐的方法。

但是,正如已经指出的那样,您确实应该在覆盖 == 时也覆盖 Equals。由于 LINQ 提供程序是用不同的语言编写并在运行时进行表达式解析,即使您自己拥有所有代码,谁知道您什么时候会因为不这样做而感到厌烦。

【讨论】:

  • 是的,这是一个常见问题,但解决方案是重写 Equals 函数并让运算符重载调用 Equals。 ReferenceEquals 解决了一个不同的问题,并提供了一种完全不同的相等类型。
  • 我认为您误解了上面的 ReferenceEquals 调用。我只是用 NULL 测试相等性,并了解另外进行实际的相等性检查。不调用 referenceequals 来测试参数的相等性。
【解决方案6】:

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

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

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

还要考虑您的 == 函数的语义:有时您真的希望能够选择是否测试

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

【讨论】:

  • 很抱歉,这真的没有回答这个问题。问题是除了向下转换之外,是否有更好的方法来测试相等性
【解决方案7】:

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

更新 我不是故意贴出来的——我更喜欢人们使用 Resharper 的功能而不是复制粘贴,因为代码会随着类的变化而变化。至于在没有 Resharper 的情况下开发 C# - 我不明白你是怎么生活的,伙计。

无论如何,这是一个简单类的代码(由旧版本 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;
}

【讨论】:

  • 你不会想为我们这些没有 400 美元的人发布它吗?
  • 为什么比尔瓦格纳会在本章中不同意你的观点? my.safaribooksonline.com/book/programming/csharp/0321245660/… 他喋喋不休地说 Equals 是对称的。
  • @Hamish - 我不知道,你必须比这更具体。
  • 等式必须是对称的。如果类 D 扩展类 B 怎么办。你永远不想要的是 b.Equals(d) 与 d.Equals(b) 不同。因此,Equals(object obj) 还应该:A) 检查 obj == null,B) 检查 this.GetType() == obj.GetType()。他是这么说的。
  • 这个实现确实包含一个空检查,虽然不是一个类型检查。有真正的代码很好,虽然严格来说你应该检查类型。
猜你喜欢
  • 2011-06-19
  • 1970-01-01
  • 2020-09-12
  • 2012-09-12
  • 1970-01-01
  • 2013-02-27
  • 2011-08-05
  • 2013-06-03
  • 2013-04-05
相关资源
最近更新 更多