6

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

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

为什么最后一个平等给我 false ?

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

4

9 回答 9

10

在字符串的情况下,当使用引用相等时,==运算符被重载以测试值相等。object

由于candd 字符串,当你Equalskand中使用时m,会使用重载方法。

并且c == dtrue出于上述原因 -string由于运算符重载,因此在类型上使用值相等。

于 2012-04-16T15:12:45.347 回答
9
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使用重载的 Stringequals方法,再次按值比较

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

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

关键是弄清楚相等性何时比较引用或值。

除非另有重载,否则对象会比较引用。

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

于 2012-04-16T15:24:36.277 回答
3

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

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

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

于 2012-04-16T15:11:10.647 回答
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指令,该指令将比较推入堆栈的值相等。压入堆栈的值是两个盒装字符串的引用,它们相等。

于 2012-04-16T15:29:10.293 回答
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()值的比较是所需的?

于 2012-04-17T18:12:35.220 回答
1

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

当您说 时object1 == object2,即使在这种情况下它们是字符串,它们也不能作为字符串来查找运算符。所以比较使用默认==操作符,它比较引用是否相等。这意味着,如果两个对象不是完全相同的对象,它将返回 false。

于 2012-04-16T15:13:34.393 回答
1

正如MSDN 上的 C# FAQ 中所见- 编译器不能使用重载方法并回退到比较引用。

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

于 2012-04-16T15:30:56.710 回答
1

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

a == b //true.

当您将它们向下转换为对象时,您只是在比较引用。 String如果另一个字符串实例已经可用,则查看内部字符串池,否则将创建一个新实例并将其添加到池中。所以实际上a,bx甚至y是同一个引用,这就是为什么

x == y //true.

使用 的构造函数String即使存在另一个具有相同值(长度和字符序列)的字符串,您也会强制 .NET 创建一个新实例。这就是为什么

k == m //false

http://en.csharp-online.net/CSharp_String_Theory%E2%80%94String_intern_pool

于 2012-04-16T15:32:28.123 回答
0

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

于 2014-07-17T21:09:38.317 回答