它们真的一样吗?今天,我遇到了这个问题。下面是立即窗口的转储:
?s
"Category"
?tvi.Header
"Category"
?s == tvi.Header
false
?s.Equals(tvi.Header)
true
?s == tvi.Header.ToString()
true
也就是s和tvi。标头包含“Category”,但==返回false, Equals()返回true。
S被定义为字符串tvi。Header实际上是WPF的TreeViewItem.Header。那么,为什么它们返回不同的结果呢?我一直认为它们在c#中是可以互换的。
有人能解释一下这是为什么吗?
除了Jon Skeet的答案,我还想解释为什么大多数情况下,当使用==时,你实际上在不同的字符串实例上得到了具有相同值的答案:
string a = "Hell";
string b = "Hello";
a = a + "o";
Console.WriteLine(a == b);
如您所见,a和b必须是不同的字符串实例,但由于字符串是不可变的,因此运行时使用所谓的字符串实习来让a和b在内存中引用相同的字符串。对象的==操作符检查引用,由于a和b引用同一个实例,结果为真。当您更改其中任何一个时,将创建一个新的字符串实例,这就是为什么字符串实习是可能的。
顺便说一下,乔恩·斯基特的回答并不完整。的确,x == y是假的,但这只是因为他在比较对象,对象通过引用进行比较。如果你写(string)x == (string)y,它会再次返回true。字符串重载了它们的==-运算符,调用String。等于下面。
两个差异:
Equals is polymorphic (i.e. it can be overridden, and the implementation used will depend on the execution-time type of the target object), whereas the implementation of == used is determined based on the compile-time types of the objects:
// Avoid getting confused by interning
object x = new StringBuilder("hello").ToString();
object y = new StringBuilder("hello").ToString();
if (x.Equals(y)) // Yes
// The compiler doesn't know to call ==(string, string) so it generates
// a reference comparision instead
if (x == y) // No
string xs = (string) x;
string ys = (string) y;
// Now *this* will call ==(string, string), comparing values appropriately
if (xs == ys) // Yes
Equals will throw an exception if you call it on null, == won't
string x = null;
string y = null;
if (x.Equals(y)) // NullReferenceException
if (x == y) // Yes
注意,使用object可以避免后者成为问题。等于:
if (object.Equals(x, y)) // Fine even if x or y is null
c#有两个“等于”概念:equals和ReferenceEquals。对于您将遇到的大多数类,==操作符使用其中一个或另一个(或两者都使用),并且通常只在处理引用类型时测试ReferenceEquals(但字符串Class是c#已经知道如何测试值相等的实例)。
Equals比较值。(即使两个独立的int变量不存在于内存中的同一位置,它们仍然可以包含相同的值。)
ReferenceEquals比较引用并返回操作数是否指向内存中的同一对象。
示例代码:
var s1 = new StringBuilder("str");
var s2 = new StringBuilder("str");
StringBuilder sNull = null;
s1.Equals(s2); // True
object.ReferenceEquals(s1, s2); // False
s1 == s2 // True - it calls Equals within operator overload
s1 == sNull // False
object.ReferenceEquals(s1, sNull); // False
s1.Equals(sNull); // Nono! Explode (Exception)
问题中出现的明显矛盾是由于在一种情况下Equals函数是在字符串对象上调用的,而在另一种情况下==操作符是在系统上调用的。对象类型。字符串和对象实现相等的方式不同(分别是值和引用)。
除此之外,任何类型都可以以不同的方式定义==和Equals,因此通常它们是不可互换的。
下面是一个使用double的例子(从Joseph Albahari的注释到c#语言规范的§7.9.2):
double x = double.NaN;
Console.WriteLine (x == x); // False
Console.WriteLine (x != x); // True
Console.WriteLine (x.Equals(x)); // True
他接着说,double. equals (double)方法被设计用来正确地处理列表和字典。另一方面,==运算符是按照IEEE 754浮点类型标准设计的。
在确定字符串相等的特定情况下,行业偏好在大多数情况下既不使用==也不使用string. equals (string)。这些方法确定两个字符串是否是相同的字符对字符,这很少是正确的行为。最好使用字符串。Equals(string, StringComparison),它允许您指定特定类型的比较。通过使用正确的比较,您可以避免许多潜在的(很难诊断的)错误。
这里有一个例子:
string one = "Caf\u00e9"; // U+00E9 LATIN SMALL LETTER E WITH ACUTE
string two = "Cafe\u0301"; // U+0301 COMBINING ACUTE ACCENT
Console.WriteLine(one == two); // False
Console.WriteLine(one.Equals(two)); // False
Console.WriteLine(one.Equals(two, StringComparison.InvariantCulture)); // True
这个例子中的两个字符串看起来是一样的("Café"),所以如果使用naïve(序数)相等,调试起来可能会非常困难。
TreeViewItem的Header属性静态类型为object类型。
因此==的结果是false。你可以用下面这个简单的代码片段重现这个过程:
object s1 = "Hallo";
// don't use a string literal to avoid interning
string s2 = new string(new char[] { 'H', 'a', 'l', 'l', 'o' });
bool equals = s1 == s2; // equals is false
equals = string.Equals(s1, s2); // equals is true