我做了一个简单的测试:
object t = 3;
object aa = 3;
#1 Console.WriteLine(t.Equals(aa));
#2 Console.WriteLine(t.Equals(3));
#3 Console.WriteLine(3.Equals(aa));
所有这些都是真的。(这实际上是我的问题)。
查看object
,这是使用过的函数:
public virtual bool Equals(object obj);
等于是虚拟的。所以它可以被覆盖。
但我不看到任何多态行为。这只是一个纯粹的盒装价值。
关于第1行t.Equals(aa)
引用类型是静态类型 - 对象。
所以我认为它应该调用Object.Equals
:这意味着引用不同,这意味着第一个答案应该是False
。(我可能在这里错了)。这是为什么?
关于第2行t.Equals(3)
同样,t's
静态类型是对象。所以Object.Equals
正在运行。怎么会true
?
关于第3行3.Equals(aa)
我认为public override bool Equals(object obj);
正在运行,因为静态类型为in
t。而param类型是对象。但为什么会true
?它取消了价值吗?
似乎有些东西在某种程度上取消了对象而没有我注意到: - (
答案 0 :(得分:8)
Object
s Equals
方法具有多态性,因此可以通过int
等子类型覆盖。 Int32.Equals重写此方法以在当前对象及其参数之间进行值比较,并且由于参数在取消装箱后相等,因此返回true。
Int32.Equals
- bool Equals(object)
和bool Equals(int)
有两个重载。 bool Equals(object)
重载是object
覆盖的重载。由于t
和aa
是object
引用,因此这是在示例1和2中调用的方法。
在示例3中,由于aa
是object
,因此仍然会调用此重载,因此这是唯一有效的重载。
==
运算符是静态的,并根据其参数的类型进行静态解析,这些参数在您的示例中均为object
。 ==
的{{1}}运算符会比较引用,在这种情况下,将为两个单独的盒装整数返回false。
答案 1 :(得分:5)
正在调用虚方法Object.Equals
,但由于虚方法的工作方式,它会调用Int32.Equals
方法,而是比较int
值,而不是引用。< / p>
虚拟方法在运行时绑定。也就是说,它们在运行时选择适当的方法,而不是在编译时。在这种情况下,Object.Equals
是编译代码中的内容,但由于您要比较int
s,它会在运行时选择Int32.Equals
。这是通过使用称为v-tables的东西来完成的(如果你想阅读更多内容)。
请记住Equals
应该这样做,如果你真的想要引用相等,你可以使用ReferenceEquals
。
请注意,这与拳击没有任何关系。您将获得相同的行为,例如,string
或自定义类。
答案 2 :(得分:0)
正如您在问题中所写,以下断言将全部通过
[Test]
public void EqualityOnInts()
{
object a = 1;
object b = 1;
Assert.AreEqual(a, b);
Assert.IsTrue(1.Equals(a));
Assert.IsTrue(b.Equals(1));
}
如果您实例化a
,则会创建一个值为1的新integer
对象。在Equals
上调用a
方法将导致调用Equals
方法在Int32
。另外,如果你做a.GetType() it will return
Int32`。
由于Equals
的{{1}}实现将检查值是否相等,并且不关心不同的对象引用,结果将为“true”。