为什么将相同的两个数字转换为Object使它们不相等?

时间:2011-02-17 17:43:10

标签: c#

我有以下代码段,但输出错误。

class Program
    {
        static void Main(string[] args)
        {
            var i = 10000;
            var j = 10000;
            Console.WriteLine((object) i == (object) j);


        }
    }

我期待的是真的,但我变得虚假

5 个答案:

答案 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的原因。