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

发布于 2024-07-05 16:02:33 字数 557 浏览 9 评论 0原文

可能的重复:
如何检查空值在没有无限递归的“==”运算符重载中?

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

    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;
    }

如果您不向下转换为对象,则函数会递归到自身,但我有想问问有没有更好的办法?

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

When I overload the == operator for objects I typically write something like this:

    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;
    }

If you don't down-cast to object the function recurses into itself but I have to wonder if there isn't a better way?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

还给你自由 2024-07-12 16:02:33

只需使用 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;
}

Just use Resharper to create you Equals & GetHashCode methods. It creates the most comprehensive code for this purpose.

Update
I didn't post it on purpose - I prefer people to use Resharper's function instead of copy-pasting, because the code changes from class to class. As for developing C# without Resharper - I don't understand how you live, man.

Anyway, here is the code for a simple class (Generated by Resharper 3.0, the older version - I have 4.0 at work, I don't currently remember if it creates identical code)

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;
}
美人迟暮 2024-07-12 16:02:33
if ((object)uq1 == null) 
    return ((object)uq2 == null)
else if ((object)uq2 == null)
    return false;
else
    //return normal comparison

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

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

This compares them as equal when both are null.

蓝颜夕 2024-07-12 16:02:33

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

@neouser99: That's the right solution, however the part that is missed is that when overriding the equality operator (the operator ==) you should also override the Equals function and simply make the operator call the function. Not all .NET languages support operator overloading, hence the reason for overriding the Equals function.

椒妓 2024-07-12 16:02:33

ReferenceEquals(对象 obj1, 对象 obj2)

ReferenceEquals(object obj1, object obj2)

本王不退位尔等都是臣 2024-07-12 16:02:33

正如微软所说,

重载中的常见错误
运算符==就是使用(a == b),(a ==
null), 或 (b == null) 来检查
参考平等。 这个代替
结果调用重载的
运算符==,导致无限循环。
使用 ReferenceEquals 或转换类型
到对象,以避免循环。

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

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

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

As Microsoft says,

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.

So use ReferenceEquals(a, null) || ReferenceEquals(b, null) is one possibility, but casting to object is just as good (is actually equivalent, I believe).

So yes, it seems there should be a better way, but the method you use is the one recommended.

However, as has been pointed out, you really SHOULD override Equals as well when overriding ==. With LINQ providers being written in different languages and doing expression resolution at runtime, who knows when you'll be bit by not doing it even if you own all the code yourself.

心头的小情儿 2024-07-12 16:02:33

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

事实上,你失去了二元运算符的对称性,但仍然......

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

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

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

But why don't you create an object member function? It can certainly not be called on a Null reference, so you're sure the first argument is not Null.

Indeed, you lose the symmetricity of a binary operator, but still...

(note on Purfideas' answer: Null might equal Null if needed as a sentinel value of an array)

Also think of the semantics of your == function: sometimes you really want to be able to choose whether you test for

  • Identity (points to same object)
  • Value Equality
  • Equivalence ( e.g. 1.000001 is equivalent to .9999999 )
情泪▽动烟 2024-07-12 16:02:33

遵循 DB 处理:

null == <anything> is always false

Follow the DB treatment:

null == <anything> is always false
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文