操作数的顺序是否对C#中的重载==运算符很重要?

时间:2015-03-09 06:43:17

标签: c# .net unity3d operator-overloading

我使用的是第三方工具(Unity3d),其中一个基本类重载了==运算符( UnityEngine.Object )。

重载运算符的签名是:

public static bool operator == (UnityEngine.Object x, UnityEngine.Object y)

进行比较的顺序是否会影响是否使用了这个重载运算符?

为了说明,它们是否应该使用重载运算符并返回相同的结果?

// initialize with some value
UnityEngine.Object a = .... 

Debug.Log(a == null);
Debug.Log(null == a);

我问的原因是因为我希望(有时)避免这种重载行为(使用默认的==运算符),并且想知道翻转订单是否有助于此?

(可能还有另一种选择 - 将操作数转换为System.object,但我并非100%确定它有效。)

3 个答案:

答案 0 :(得分:3)

更新问题后更新:

如果您想在与null比较时避免调用重载函数,请使用ReferenceEquals

if(a.ReferenceEquals(null)) ...

老人的回答,已被淘汰,并且@Jon Skeet也错了......

根据this,使用X和Y作为参数的二元运算符的重载决策是通过首先获取由X和Y定义的所有运算符的并集来完成的。

因此a==b会产生与b==a完全相同的重载分辨率。

该链接来自2003年,但我怀疑微软已经改变了一些东西,因为它会破坏很多的旧代码。

答案 1 :(得分:3)

嗯,如果运营商严重超载,那么这两个电话可能不会相同。可能有一个重载,它可以用不对称地比较操作数的方式编写,或者两个语句可以调用不同的重载。

但假设它正确,那应该是绝对正常的。当然,如果您想要来调用重载运算符,那就是这样。如果您不这样做,我会使用ReferenceEquals清楚地表明这一点。

我个人推荐if (a == null)方法,因为我觉得它更容易阅读(我相信很多其他人也这样做)。 " yoda" if (null == a)的样式有时会被那些担心拼写错误的程序员使用,其中if (a = null)将是一个赋值和一个有效的陈述......虽然在正确的C编译器中有警告。

这是一个严重实现的重载集的示例,其中操作数顺序很重要,因为null可以转换为string和{{1 }}:

Test

既然问题已经更新,我们可以说情况并非如此......但实施可能仍然很差。例如,可以写成:

using System;

class Test
{
    public static bool operator ==(Test t, string x)
    {
        Console.WriteLine("Test == string");
        return false;
    }

    public static bool operator !=(Test t, string x)
    {
        Console.WriteLine("Test != string");
        return false;
    }

    public static bool operator ==(string x, Test t)
    {
        Console.WriteLine("string == Test");
        return false;
    }

    public static bool operator !=(string x, Test t)
    {
        Console.WriteLine("string != Test");
        return false;
    }

    static void Main(string[] args)
    {
        Test t = null;
        Console.WriteLine(t == null);
        Console.WriteLine(null == t);
    }
}

在这种情况下,当public static bool operator == (UnityEngine.Object x, UnityEngine.Object y) { // Awful implementation - do not use! return x.Equals(y); } 为空时,它将失败并显示NullReferenceException,但如果x为非空但x为空,则会失败(假设为{{ 1}}已经写好了。

尽管如此,我期待操作员已正确编写,并且这不是问题。

答案 2 :(得分:1)

更新虽然我在Unity的早期版本中目睹了这种行为,但我无法在编写此答案后立即执行的测试中重现它。可能是Unity更改了==运算符行为,或UnityEngine.Object隐式转换为bool的行为;但是,我仍然主张使用重写的==运算符,而不是试图避免它。

Unity特别优先覆盖==运算符的方式非常令人沮丧,但也是您必须使用引擎的基础。 UnityObject被销毁后,通过调用Destroy(调用后一段时间)或DestroyImmediate(调用后立即调用,如名称所示),将此对象与null进行比较返回true ,即使它不是空引用。

对于C#程序员来说,这完全不直观,并且在你弄明白之前可以创造很多真正的WTF时刻。拿这个,例如:

DestroyImmediately(someObject);
if (someObject)
{
    Debug.Log("This gets printed");
}
if (someObject != null)
{
    Debug.Log("This doesn't");
}

我之所以解释这是因为我完全理解你想要避免这种奇怪的被覆盖的行为,特别是如果你在使用Unity之前有C#经验。但是,与许多其他Unity特定的东西一样,实际上更好的是坚持Unity约定而不是尝试以C#正确的方式实现所有内容。