我有这些陈述,他们的'结果就在他们附近。
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)为假
答案 0 :(得分:10)
对于字符串,当使用==
引用相等时,object
运算符被重载以测试值的相等性。
由于c
和d
是字符串,当您在Equals
和k
中使用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 ,a
和b
都是对同一字符串对象的引用。
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,否则将创建一个新实例并将其添加到池中。实际上a
,b
,x
和y
实际上是相同的参考,这就是
x == y //true
。
使用String
的{{3}},即使存在具有相同值(长度和字符序列)的另一个字符串,也会强制.NET创建新实例。这就是
k == m //false
答案 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则比较实际对象值。在字符串的情况下,你很幸运,两个相同的字符串可以经常引用相同的地址。托管语言的乐趣之一。