.NET中的对象相等性行为不同

时间:2012-04-16 15:08:35

标签: c# .net

我有这些陈述,他们的'结果就在他们附近。

string a = "abc";
string b = "abc";

Console.Writeline(a == b); //true

object x = a;
object y = b;

Console.Writeline(x == y); // true

string c = new string(new char[] {'a','b','c'});
string d = new string(new char[] {'a','b','c'});

Console.Writeline(c == d); // true

object k = c;
object m = d;

Console.Writeline(k.Equals(m)) //true

Console.Writeline(k == m); // false

为什么最后的平等会让我错误?

问题是为什么(x == y)为真(k == m)为假

9 个答案:

答案 0 :(得分:10)

对于字符串,当使用==引用相等时,object运算符被重载以测试值的相等性。

由于cd 字符串,当您在Equalsk中使用m时,重载的方法使用。

c == d因{ - 1}}状态而导致上述状态 - 由于运算符过载,因此true类型使用了值相等。

答案 1 :(得分:8)

string a = "abc"; 
string b = "abc"; 

Console.Writeline(a == b); //true 

由于 String Interning

,字符串引用对于相同的字符串是相同的
object x = a; 
object y = b; 

Console.Writeline(x == y); // true 

因为引用相同,所以从同一引用创建的两个对象也是相同的。

string c = new string(new char[] {'a','b','c'}); 
string d = new string(new char[] {'a','b','c'}); 

在这里创建两个新的字符数组,这些引用是不同的。

Console.Writeline(c == d); // true 

字符串已超载==按值进行比较。

object k = c; 
object m = d; 

由于先前的引用不同,因此这些对象是不同的。

Console.Writeline(k.Equals(m)) //true 

.Equals使用重载的String equals方法,该方法再次按值

进行比较
Console.Writeline(k == m); // false 

在这里,我们检查两个引用是否相同......它们不是

关键在于确定何时等于比较参考或值。

除非另外重载,否则

对象比较引用。

结构,除非另有重载,否则比较值。

答案 2 :(得分:3)

因为它们是两个不同的对象引用。对此的内置比较是比较它们是否指向相同的实际对象。

由于 String Interning ab都是对同一字符串对象的引用。

c==d为true,因为正在使用字符串相等运算符。

答案 3 :(得分:2)

   string c = new string(new char[] {'a','b','c'});
   string d = new string(new char[] {'a','b','c'});

   Console.WriteLine(c == d); // true

   object k = c;
   object m = d;

   Console.WriteLine(k.Equals(m)); //true

   Console.WriteLine(k == m); // false

生成IL代码,如下所示:

IL_0001:  ldc.i4.3    
IL_0002:  newarr      System.Char
IL_0007:  dup         
IL_0008:  ldtoken     <PrivateImplementationDetails>{61BB33F4-0CA5-4733-B259-764124AD1A79}.$$method0x6000002-1
IL_000D:  call        System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray
IL_0012:  newobj      System.String..ctor
IL_0017:  stloc.0     
IL_0018:  ldc.i4.3    
IL_0019:  newarr      System.Char
IL_001E:  dup         
IL_001F:  ldtoken     <PrivateImplementationDetails>{61BB33F4-0CA5-4733-B259-764124AD1A79}.$$method0x6000002-2
IL_0024:  call        System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray
IL_0029:  newobj      System.String..ctor
IL_002E:  stloc.1     
IL_002F:  ldloc.0     
IL_0030:  ldloc.1     
IL_0031:  call        System.String.op_Equality   //STRING EQUALITY 
IL_0036:  call        System.Console.WriteLine
IL_003B:  nop         
IL_003C:  ldloc.0     
IL_003D:  stloc.2     
IL_003E:  ldloc.1     
IL_003F:  stloc.3     
IL_0040:  ldloc.2     
IL_0041:  ldloc.3     
IL_0042:  callvirt    System.Object.Equals
IL_0047:  call        System.Console.WriteLine
IL_004C:  nop         
IL_004D:  ldloc.2     
IL_004E:  ldloc.3     
IL_004F:  ceq         //CEQ INSTRUCTION: **VALUES** EQUALITY !
IL_0051:  call        System.Console.WriteLine

正如您所看到的那样,最后一条指令调用CEQ指令使得在堆栈上推送的值相等。堆栈上推送的值是两个盒装字符串的引用,它们相等。

答案 4 :(得分:1)

当您说string1 == string2时,比较会使用string类型的重载==运算符,该运算符会比较字符串的值。

当你说object1 == object2时,即使它们在这种情况下是字符串,它们也不会被用作查找运算符的字符串。因此,比较使用默认的==运算符,该运算符将引用进行比较以获得相等性。这意味着,如果两个对象不是完全相同的对象,则返回false。

答案 5 :(得分:1)

C# FAQ on MSDN所示 - 编译器不能使用重载方法,而是回退到比较引用。

更大的问题是为什么它在第一次对象比较中取得成功。我最好的猜测是成功,因为a和b都给出了相同的参考。对于c和d,您强制使用不同的引用。

答案 6 :(得分:1)

String重载了相等运算符,以便您可以使用==进行值比较。因此

a == b //true

当您将它们转发为对象时,您只需比较引用。 如果另一个字符串实例已经可用,String会查看内部string-pool,否则将创建一个新实例并将其添加到池中。实际上abxy实际上是相同的参考,这就是

的原因

x == y //true

使用String的{​​{3}},即使存在具有相同值(长度和字符序列)的另一个字符串,也会强制.NET创建新实例。这就是

的原因

k == m //false

constructor

答案 7 :(得分:1)

在Bob2Chiv的基础上,我尝试了VB中的等价物(VS2010):

    Dim a As String = "abc"
    Dim b As String = "abc"

    Console.WriteLine(a = b) ' True

    Dim x As Object = a
    Dim y As Object = b

    Console.WriteLine(x = y) ' True

    Dim c As String = New String(New Char() {"a"c, "b"c, "c"c})
    Dim d As String = New String(New Char() {"a"c, "b"c, "c"c})

    Console.WriteLine(c = d) ' True

    Dim k As Object = c
    Dim m As Object = d

    Console.WriteLine(k.Equals(m)) ' True

    Console.WriteLine(k = m) ' True (Yes, True!!)

    Console.WriteLine(k Is m) ' False (Like in C#)

    Console.WriteLine(a Is b) ' True (Like in C#)

(至少我认为这是相同的 - 我欢迎在此纠正。)

道德?:在C#中注意== - 当值的比较符合要求时,更喜欢.Equals()

答案 8 :(得分:0)

==运算符比较引用(内存地址),而.Equals则比较实际对象值。在字符串的情况下,你很幸运,两个相同的字符串可以经常引用相同的地址。托管语言的乐趣之一。