我有以下代码段,但输出错误。
class Program
{
static void Main(string[] args)
{
var i = 10000;
var j = 10000;
Console.WriteLine((object) i == (object) j);
}
}
我期待的是真的,但我变得虚假
答案 0 :(得分:21)
您正在装箱数字(通过对象强制转换),为每个变量创建一个新实例。对象的==
运算符基于对象标识(也称为引用相等),因此您看到false
(因为实例不相同)
要正确比较这些对象,您可以使用Object.Equals(i, j)
或i.Equals(j)
。这将起作用,因为对象的实际运行时实例将为Int32
,其Equals()
方法具有正确的整数等式语义。
答案 1 :(得分:5)
您正在使用==
,默认情况下会调用ReferenceEquals
。你应该使用:
Console.WriteLine(((object)i).Equals((object)j));
答案 2 :(得分:2)
因为您正在比较两个不同的对象,原因就在于此。
答案 3 :(得分:1)
它们是两个不同的对象,永远不会是平等的。他们的价值是相等的。
答案 4 :(得分:1)
操作符已重载,未被覆盖。这意味着将在编译时而不是在运行时确定将调用的实际方法。要理解这种差异,你应该这样想:
假设您有以下代码
public class MyBase
{
public virtual void DoSomething() { Console.WriteLine("Base"); }
}
public class A : MyBase
{
public override void DoSomething() { Console.WriteLine("A"); }
}
public class B : MyBase
{
public override void DoSomething() { Console.WriteLine("B"); }
}
现在您可以创建A和B的实例:
MyBase a = new A();
MyBase b = new B();
a.DoSomething(); // prints "A"
b.DoSomething(); // prints "B"
MyBase的每个实例都包含对vtable的隐藏引用,该引用指向必须调用的DoSomething()
的实际实现。因此,当运行时需要在DoSomething()
上调用a
时,它将查看a
的vtable,并找到打印"A"
的版本。 重要的是,这在运行时发生。
现在,当您重载方法时,您将创建一个具有相同名称但具有不同签名的方法。
public class C
{
public void Print(string str) { Console.WriteLine("string: " + string); }
public void Print(int i) { Console.WriteLine("int: " + i); }
public void Print(object obj) { Console.WriteLine("object: " + obj.ToString()); }
}
var c = new C();
c.Print("1"); // string: 1
c.Print(1); // int: 1
c.Print((object)1); // object: 1
这次编译器决定调用哪个方法而不是运行时。编译器不是很聪明。当它看到(object)1
时,它会看到对象的引用,编译器会尝试查找可以将对象作为参数的Print()
版本。
有时编译器会找到两个可以使用的版本。例如,"1"
是一个字符串,但它也是一个对象,因此Print()
的第一个和第三个版本都能够接受字符串。在这种情况下,编译器选择具有最特定参数类型的版本。有时编译器无法选择,如下例所示:
public static void Print(string a, object b) { Console.WriteLine("V1"); }
public static void Print(object a, string b) { Console.WriteLine("V2"); }
Print("a", "b"); // does this print "V1" or "V2"?
在这种情况下,没有一个版本比另一个版本更具体,因此编译器会产生编译器错误:以下方法或属性之间的调用是不明确的:'Test.Program.Print(string,object )'和'Test.Program.Print(object,string)'
正如我在开头所说,==
运算符已超载。这意味着编译器选择使用哪个版本。最通用的版本是两个操作数都是Object
类型的版本。此版本比较参考。这就是(object) i == (object) j
返回false的原因。