string.Equals()和==操作符是相同的吗?(复制)

时间:2022-02-28 16:15:40

This question already has an answer here:

这个问题已经有了答案:

Are they really same? Today, I ran into this problem. Here is the dump from the Immediate Window:

他们是相同的吗?今天,我遇到了这个问题。这里是即时窗口的转储:

?s 
"Category" 
?tvi.Header 
"Category" 
?s == tvi.Header 
false 
?s.Equals(tvi.Header) 
true 
?s == tvi.Header.ToString() 
true 

So, both s and tvi.Header contain "Category", but == returns false and Equals() returns true.

所以,s和tvi。头包含“类别”,但==返回false, Equals()返回true。

s is defined as string, tvi.Header is actually a WPF TreeViewItem.Header. So, why are they returning different results? I always thought that they were interchangable in C#.

s被定义为字符串tvi。Header实际上是WPF TreeViewItem.Header。那么,他们为什么要返回不同的结果呢?我一直认为它们在c#中是可互换的。

Can anybody explain why this is?

有人能解释一下吗?

8 个解决方案

#1


313  

Two differences:

两个差异:

  • 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:

    Equals是多态的(也就是说,它可以被重写,并且使用的实现依赖于目标对象的executiontime类型),而==使用的实现是基于对象的编译时类型决定的:

    // 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 go bang if you call it on null, == won't

    如果你把它命名为null, ==不会。

    string x = null;
    string y = null;
    
    if (x.Equals(y)) // Bang
    
    if (x == y) // Yes
    

Note that you can avoid the latter being a problem using object.Equals:

请注意,您可以避免使用object.Equals:

if (object.Equals(x, y)) // Fine even if x or y is null

#2


47  

The apparent contradictions that appear in the question are caused because in one case the Equals function is called on a string object, and in the other case the == operator is called on the System.Object type. string and object implement equality differently from each other (value vs. reference respectively).

在这个问题中出现的明显的矛盾是由于在一个情况下,在一个字符串对象上调用了Equals函数,在另一个情况下,在系统上调用==操作符。对象类型。字符串和对象以不同的方式实现相等(值vs.引用)。

Beyond this fact, any type can define == and Equals differently, so in general they are not interchangeable.

除了这个事实之外,任何类型都可以定义==和=不同,所以一般来说它们是不可互换的。

Here’s an example using double (from Joseph Albahari’s note to §7.9.2 of the C# language specification):

这里有一个使用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

He goes on to say that the double.Equals(double) method was designed to work correctly with lists and dictionaries. The == operator, on the other hand, was designed to follow the IEEE 754 standard for floating point types.

他接着说,double.Equals(double)方法被设计用来正确地处理列表和字典。另一方面,==操作符被设计为遵循IEEE 754的浮点类型标准。

In the specific case of determining string equality, the industry preference is to use neither == nor string.Equals(string) most of the time. These methods determine whether two string are the same character-for-character, which is rarely the correct behavior. It is better to use string.Equals(string, StringComparison), which allows you to specify a particular type of comparison. By using the correct comparison, you can avoid a lot of potential (very hard to diagnose) bugs.

在确定字符串相等的具体情况下,行业首选项是在大多数情况下都不使用==或string. equals (string)。这些方法确定两个字符串是否相同字符,这很少是正确的行为。最好使用字符串。Equals(string, stringcompare),它允许您指定特定类型的比较。通过使用正确的比较,您可以避免许多潜在的(很难诊断)错误。

Here’s one example:

这里有一个例子:

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

Both strings in this example look the same ("Café"), so this could be very tough to debug if using a naïve (ordinal) equality.

在这个示例中,两个字符串看起来都一样(“Cafe”),因此如果使用一个简单的(顺序的)等式,就很难进行调试。

#3


41  

C# has two "equals" concepts: Equals and ReferenceEquals. For most classes you will encounter, the == operator uses one or the other (or both), and generally only tests for ReferenceEquals when handling reference types (but the string Class is an instance where C# already knows how to test for value equality).

c#有两个“equals”概念:equals和ReferenceEquals。对于大多数您将遇到的类,==操作符使用一个或另一个(或两者),并且通常只在处理引用类型时进行引用的测试(但是string类是c#已经知道如何测试值相等的一个实例)。

  • Equals compares values. (Even though two separate int variables don't exist in the same spot in memory, they can still contain the same value.)
  • =比较值。(即使两个单独的int变量在内存中不存在,它们仍然可以包含相同的值。)
  • ReferenceEquals compares the reference and returns whether the operands point to the same object in memory.
  • ReferenceEquals对引用进行比较,并返回在内存中操作数指向同一个对象的情况。

Example Code:

示例代码:

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)

#4


15  

The Header property of the TreeViewItem is statically typed to be of type object.

TreeViewItem的头属性被静态类型化为类型对象。

Therefore the == yields false. You can reproduce this with the following simple snippet:

因此,==产生假。您可以通过以下简单的代码片段来复制这个:

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

#5


4  

In addition to Jon Skeet's answer, I'd like to explain why most of the time when using == you actually get the answer true on different string instances with the same value:

除了Jon Skeet的回答之外,我还想解释为什么大多数时候在使用==时,您可以在具有相同值的不同字符串实例上得到正确的答案:

string a = "Hell";
string b = "Hello";
a = a + "o";
Console.WriteLine(a == b);

As you can see, a and b must be different string instances, but because strings are immutable, the runtime uses so called string interning to let both a and b reference the same string in memory. The == operator for objects checks reference, and since both a and b reference the same instance, the result is true. When you change either one of them, a new string instance is created, which is why string interning is possible.

正如您所看到的,a和b必须是不同的字符串实例,但是由于字符串是不可变的,所以运行时使用所谓的string interning来让a和b在内存中引用相同的字符串。对象的==操作符检查引用,由于a和b都引用相同的实例,结果是正确的。当您更改其中之一时,就会创建一个新的字符串实例,这就是为什么string interning是可能的。

By the way, Jon Skeet's answer is not complete. Indeed, x == y is false but that is only because he is comparing objects and objects compare by reference. If you'd write (string)x == (string)y, it will return true again. So strings have their ==-operator overloaded, which calls String.Equals underneath.

顺便说一下,Jon Skeet的答案还不完整。的确,x == y是错误的,但这只是因为他比较对象和对象比较引用。如果你写入(string)x == (string)y,它将返回true。字符串有==-运算符重载,调用字符串。等于下面。

#6


4  

There are plenty of descriptive answers here so I'm not going to repeat what has already been said. What I would like to add is the following code demonstrating all the permutations I can think of. The code is quite long due to the number of combinations. Feel free to drop it into MSTest and see the output for yourself (the output is included at the bottom).

这里有很多描述性的答案,所以我不会重复已经说过的内容。我想添加的是下面的代码,它展示了我所能想到的所有排列。由于组合的数量,代码很长。请随意将其放入MSTest中并查看输出(输出包含在底部)。

This evidence supports Jon Skeet's answer.

这一证据支持了Jon Skeet的回答。

Code:

代码:

[TestMethod]
public void StringEqualsMethodVsOperator()
{
    string s1 = new StringBuilder("string").ToString();
    string s2 = new StringBuilder("string").ToString();

    Debug.WriteLine("string a = \"string\";");
    Debug.WriteLine("string b = \"string\";");

    TryAllStringComparisons(s1, s2);

    s1 = null;
    s2 = null;

    Debug.WriteLine(string.Join(string.Empty, Enumerable.Repeat("-", 20)));
    Debug.WriteLine(string.Empty);
    Debug.WriteLine("string a = null;");
    Debug.WriteLine("string b = null;");

    TryAllStringComparisons(s1, s2);
}
private void TryAllStringComparisons(string s1, string s2)
{
    Debug.WriteLine(string.Empty);
    Debug.WriteLine("-- string.Equals --");
    Debug.WriteLine(string.Empty);
    Try((a, b) => string.Equals(a, b), s1, s2);
    Try((a, b) => string.Equals((object)a, b), s1, s2);
    Try((a, b) => string.Equals(a, (object)b), s1, s2);
    Try((a, b) => string.Equals((object)a, (object)b), s1, s2);

    Debug.WriteLine(string.Empty);
    Debug.WriteLine("-- object.Equals --");
    Debug.WriteLine(string.Empty);
    Try((a, b) => object.Equals(a, b), s1, s2);
    Try((a, b) => object.Equals((object)a, b), s1, s2);
    Try((a, b) => object.Equals(a, (object)b), s1, s2);
    Try((a, b) => object.Equals((object)a, (object)b), s1, s2);

    Debug.WriteLine(string.Empty);
    Debug.WriteLine("-- a.Equals(b) --");
    Debug.WriteLine(string.Empty);
    Try((a, b) => a.Equals(b), s1, s2);
    Try((a, b) => a.Equals((object)b), s1, s2);
    Try((a, b) => ((object)a).Equals(b), s1, s2);
    Try((a, b) => ((object)a).Equals((object)b), s1, s2);

    Debug.WriteLine(string.Empty);
    Debug.WriteLine("-- a == b --");
    Debug.WriteLine(string.Empty);
    Try((a, b) => a == b, s1, s2);
#pragma warning disable 252
    Try((a, b) => (object)a == b, s1, s2);
#pragma warning restore 252
#pragma warning disable 253
    Try((a, b) => a == (object)b, s1, s2);
#pragma warning restore 253
    Try((a, b) => (object)a == (object)b, s1, s2);
}
public void Try<T1, T2, T3>(Expression<Func<T1, T2, T3>> tryFunc, T1 in1, T2 in2)
{
    T3 out1;

    Try(tryFunc, e => { }, in1, in2, out out1);
}
public bool Try<T1, T2, T3>(Expression<Func<T1, T2, T3>> tryFunc, Action<Exception> catchFunc, T1 in1, T2 in2, out T3 out1)
{
    bool success = true;
    out1 = default(T3);

    try
    {
        out1 = tryFunc.Compile()(in1, in2);
        Debug.WriteLine("{0}: {1}", tryFunc.Body.ToString(), out1);
    }
    catch (Exception ex)
    {
        Debug.WriteLine("{0}: {1} - {2}", tryFunc.Body.ToString(), ex.GetType().ToString(), ex.Message);
        success = false;
        catchFunc(ex);
    }

    return success;
}

Output:

输出:

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

-- string.Equals --

Equals(a, b): True
Equals(Convert(a), b): True
Equals(a, Convert(b)): True
Equals(Convert(a), Convert(b)): True

-- object.Equals --

Equals(a, b): True
Equals(Convert(a), b): True
Equals(a, Convert(b)): True
Equals(Convert(a), Convert(b)): True

-- a.Equals(b) --

a.Equals(b): True
a.Equals(Convert(b)): True
Convert(a).Equals(b): True
Convert(a).Equals(Convert(b)): True

-- a == b --

(a == b): True
(Convert(a) == b): False
(a == Convert(b)): False
(Convert(a) == Convert(b)): False
--------------------

string a = null;
string b = null;

-- string.Equals --

Equals(a, b): True
Equals(Convert(a), b): True
Equals(a, Convert(b)): True
Equals(Convert(a), Convert(b)): True

-- object.Equals --

Equals(a, b): True
Equals(Convert(a), b): True
Equals(a, Convert(b)): True
Equals(Convert(a), Convert(b)): True

-- a.Equals(b) --

a.Equals(b): System.NullReferenceException - Object reference not set to an instance of an object.
a.Equals(Convert(b)): System.NullReferenceException - Object reference not set to an instance of an object.
Convert(a).Equals(b): System.NullReferenceException - Object reference not set to an instance of an object.
Convert(a).Equals(Convert(b)): System.NullReferenceException - Object reference not set to an instance of an object.

-- a == b --

(a == b): True
(Convert(a) == b): True
(a == Convert(b)): True
(Convert(a) == Convert(b)): True

#7


3  

It is clear that tvi.header is not a String. The == is an operator that is overloaded by String class, which means it will be working only if compiler knows that both side of the operator are String.

很明显,tvi。header不是字符串。==是一个由String类重载的操作符,这意味着只有当编译器知道操作符的两边是字符串时才会运行。

#8


-1  

An object is defined by an OBJECT_ID, which is unique. If A and B are objects and A == B is true, then they are the very same object, they have the same data and methods, but, this is also true:

对象由OBJECT_ID定义,它是惟一的。如果A和B是对象,A == B是真的,那么它们是相同的对象,它们有相同的数据和方法,但是,这也是正确的:

A.OBJECT_ID == B.OBJECT_ID

一个。OBJECT_ID = = B.OBJECT_ID

if A.Equals(B) is true, that means that the two objects are in the same state, but this doesn't mean that A is the very same as B.

如果A = (B)为真,那就意味着这两个对象处于同一状态,但这并不意味着A和B是一样的。

Strings are objects.

字符串是对象。

Note that the == and Equals operators are reflexive, simetric, tranzitive, so they are equivalentic relations (to use relational algebraic terms)

注意==和等于运算符是自反的,simetric, tranzitive,所以它们是相等的关系(使用关系代数术语)

What this means: If A, B and C are objects, then:

这意味着:如果A、B和C是对象,那么:

(1) A == A is always true; A.Equals(A) is always true (reflexivity)

(1)A == A始终为真;A. = (A)始终为真(自反性)

(2) if A == B then B == A; If A.Equals(B) then B.Equals(A) (simetry)

(2)如果A == B,则B == A;如果A等于(B)那么B = (A) (simetry)

(3) if A == B and B == C, then A == C; if A.Equals(B) and B.Equals(C) then A.Equals(C) (tranzitivity)

(3)if A == B和B == C,则A == C;如果a等于(B)和B = (C)那么a = (C) (tranzitivity)

Also, you can note that this is also true:

同样,你可以注意到这也是正确的:

(A == B) => (A.Equals(B)), but the inverse is not true.

(A == B) => (A = B),但逆是不成立的。

A B =>
0 0 1
0 1 1
1 0 0
1 1 1

Example of real life: Two Hamburgers of the same type have the same properties: they are objects of the Hamburger class, their properties are exactly the same, but they are different entities. If you buy these two Hamburgers and eat one, the other one won't be eaten. So, the difference between Equals and ==: You have hamburger1 and hamburger2. They are exactly in the same state (the same weight, the same temperature, the same taste), so hamburger1.Equals(hamburger2) is true. But hamburger1 == hamburger2 is false, because if the state of hamburger1 changes, the state of hamburger2 not necessarily change and vice versa.

现实生活的例子:两个相同类型的汉堡具有相同的属性:它们是汉堡类的对象,它们的属性完全相同,但它们是不同的实体。如果你买这两个汉堡,吃一个,另一个就不会被吃掉。所以,等号和==的区别是:你有hamburger1和hamburger2。它们完全处于相同的状态(相同的重量,相同的温度,相同的味道),所以hamburger1.Equals(hamburger2)是正确的。但是hamburger1 == hamburger2是假的,因为如果hamburger1的状态发生变化,hamburger2的状态不一定会改变,反之亦然。

If you and a friend get a Hamburger, which is yours and his in the same time, then you must decide to split the Hamburger into two parts, because you.getHamburger() == friend.getHamburger() is true and if this happens: friend.eatHamburger(), then your Hamburger will be eaten too.

如果你和一个朋友买了一个汉堡包,这是你的,同时也是他的,那么你必须决定把汉堡分成两份,因为你要吃汉堡()。

I could write other nuances about Equals and ==, but I'm getting hungry, so I have to go.

我可以写其他关于等号和==的细微差别,但是我饿了,所以我得走了。

Best regards, Lajos Arpad.

最好的问候,Lajos亚珥拔。

#1


313  

Two differences:

两个差异:

  • 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:

    Equals是多态的(也就是说,它可以被重写,并且使用的实现依赖于目标对象的executiontime类型),而==使用的实现是基于对象的编译时类型决定的:

    // 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 go bang if you call it on null, == won't

    如果你把它命名为null, ==不会。

    string x = null;
    string y = null;
    
    if (x.Equals(y)) // Bang
    
    if (x == y) // Yes
    

Note that you can avoid the latter being a problem using object.Equals:

请注意,您可以避免使用object.Equals:

if (object.Equals(x, y)) // Fine even if x or y is null

#2


47  

The apparent contradictions that appear in the question are caused because in one case the Equals function is called on a string object, and in the other case the == operator is called on the System.Object type. string and object implement equality differently from each other (value vs. reference respectively).

在这个问题中出现的明显的矛盾是由于在一个情况下,在一个字符串对象上调用了Equals函数,在另一个情况下,在系统上调用==操作符。对象类型。字符串和对象以不同的方式实现相等(值vs.引用)。

Beyond this fact, any type can define == and Equals differently, so in general they are not interchangeable.

除了这个事实之外,任何类型都可以定义==和=不同,所以一般来说它们是不可互换的。

Here’s an example using double (from Joseph Albahari’s note to §7.9.2 of the C# language specification):

这里有一个使用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

He goes on to say that the double.Equals(double) method was designed to work correctly with lists and dictionaries. The == operator, on the other hand, was designed to follow the IEEE 754 standard for floating point types.

他接着说,double.Equals(double)方法被设计用来正确地处理列表和字典。另一方面,==操作符被设计为遵循IEEE 754的浮点类型标准。

In the specific case of determining string equality, the industry preference is to use neither == nor string.Equals(string) most of the time. These methods determine whether two string are the same character-for-character, which is rarely the correct behavior. It is better to use string.Equals(string, StringComparison), which allows you to specify a particular type of comparison. By using the correct comparison, you can avoid a lot of potential (very hard to diagnose) bugs.

在确定字符串相等的具体情况下,行业首选项是在大多数情况下都不使用==或string. equals (string)。这些方法确定两个字符串是否相同字符,这很少是正确的行为。最好使用字符串。Equals(string, stringcompare),它允许您指定特定类型的比较。通过使用正确的比较,您可以避免许多潜在的(很难诊断)错误。

Here’s one example:

这里有一个例子:

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

Both strings in this example look the same ("Café"), so this could be very tough to debug if using a naïve (ordinal) equality.

在这个示例中,两个字符串看起来都一样(“Cafe”),因此如果使用一个简单的(顺序的)等式,就很难进行调试。

#3


41  

C# has two "equals" concepts: Equals and ReferenceEquals. For most classes you will encounter, the == operator uses one or the other (or both), and generally only tests for ReferenceEquals when handling reference types (but the string Class is an instance where C# already knows how to test for value equality).

c#有两个“equals”概念:equals和ReferenceEquals。对于大多数您将遇到的类,==操作符使用一个或另一个(或两者),并且通常只在处理引用类型时进行引用的测试(但是string类是c#已经知道如何测试值相等的一个实例)。

  • Equals compares values. (Even though two separate int variables don't exist in the same spot in memory, they can still contain the same value.)
  • =比较值。(即使两个单独的int变量在内存中不存在,它们仍然可以包含相同的值。)
  • ReferenceEquals compares the reference and returns whether the operands point to the same object in memory.
  • ReferenceEquals对引用进行比较,并返回在内存中操作数指向同一个对象的情况。

Example Code:

示例代码:

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)

#4


15  

The Header property of the TreeViewItem is statically typed to be of type object.

TreeViewItem的头属性被静态类型化为类型对象。

Therefore the == yields false. You can reproduce this with the following simple snippet:

因此,==产生假。您可以通过以下简单的代码片段来复制这个:

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

#5


4  

In addition to Jon Skeet's answer, I'd like to explain why most of the time when using == you actually get the answer true on different string instances with the same value:

除了Jon Skeet的回答之外,我还想解释为什么大多数时候在使用==时,您可以在具有相同值的不同字符串实例上得到正确的答案:

string a = "Hell";
string b = "Hello";
a = a + "o";
Console.WriteLine(a == b);

As you can see, a and b must be different string instances, but because strings are immutable, the runtime uses so called string interning to let both a and b reference the same string in memory. The == operator for objects checks reference, and since both a and b reference the same instance, the result is true. When you change either one of them, a new string instance is created, which is why string interning is possible.

正如您所看到的,a和b必须是不同的字符串实例,但是由于字符串是不可变的,所以运行时使用所谓的string interning来让a和b在内存中引用相同的字符串。对象的==操作符检查引用,由于a和b都引用相同的实例,结果是正确的。当您更改其中之一时,就会创建一个新的字符串实例,这就是为什么string interning是可能的。

By the way, Jon Skeet's answer is not complete. Indeed, x == y is false but that is only because he is comparing objects and objects compare by reference. If you'd write (string)x == (string)y, it will return true again. So strings have their ==-operator overloaded, which calls String.Equals underneath.

顺便说一下,Jon Skeet的答案还不完整。的确,x == y是错误的,但这只是因为他比较对象和对象比较引用。如果你写入(string)x == (string)y,它将返回true。字符串有==-运算符重载,调用字符串。等于下面。

#6


4  

There are plenty of descriptive answers here so I'm not going to repeat what has already been said. What I would like to add is the following code demonstrating all the permutations I can think of. The code is quite long due to the number of combinations. Feel free to drop it into MSTest and see the output for yourself (the output is included at the bottom).

这里有很多描述性的答案,所以我不会重复已经说过的内容。我想添加的是下面的代码,它展示了我所能想到的所有排列。由于组合的数量,代码很长。请随意将其放入MSTest中并查看输出(输出包含在底部)。

This evidence supports Jon Skeet's answer.

这一证据支持了Jon Skeet的回答。

Code:

代码:

[TestMethod]
public void StringEqualsMethodVsOperator()
{
    string s1 = new StringBuilder("string").ToString();
    string s2 = new StringBuilder("string").ToString();

    Debug.WriteLine("string a = \"string\";");
    Debug.WriteLine("string b = \"string\";");

    TryAllStringComparisons(s1, s2);

    s1 = null;
    s2 = null;

    Debug.WriteLine(string.Join(string.Empty, Enumerable.Repeat("-", 20)));
    Debug.WriteLine(string.Empty);
    Debug.WriteLine("string a = null;");
    Debug.WriteLine("string b = null;");

    TryAllStringComparisons(s1, s2);
}
private void TryAllStringComparisons(string s1, string s2)
{
    Debug.WriteLine(string.Empty);
    Debug.WriteLine("-- string.Equals --");
    Debug.WriteLine(string.Empty);
    Try((a, b) => string.Equals(a, b), s1, s2);
    Try((a, b) => string.Equals((object)a, b), s1, s2);
    Try((a, b) => string.Equals(a, (object)b), s1, s2);
    Try((a, b) => string.Equals((object)a, (object)b), s1, s2);

    Debug.WriteLine(string.Empty);
    Debug.WriteLine("-- object.Equals --");
    Debug.WriteLine(string.Empty);
    Try((a, b) => object.Equals(a, b), s1, s2);
    Try((a, b) => object.Equals((object)a, b), s1, s2);
    Try((a, b) => object.Equals(a, (object)b), s1, s2);
    Try((a, b) => object.Equals((object)a, (object)b), s1, s2);

    Debug.WriteLine(string.Empty);
    Debug.WriteLine("-- a.Equals(b) --");
    Debug.WriteLine(string.Empty);
    Try((a, b) => a.Equals(b), s1, s2);
    Try((a, b) => a.Equals((object)b), s1, s2);
    Try((a, b) => ((object)a).Equals(b), s1, s2);
    Try((a, b) => ((object)a).Equals((object)b), s1, s2);

    Debug.WriteLine(string.Empty);
    Debug.WriteLine("-- a == b --");
    Debug.WriteLine(string.Empty);
    Try((a, b) => a == b, s1, s2);
#pragma warning disable 252
    Try((a, b) => (object)a == b, s1, s2);
#pragma warning restore 252
#pragma warning disable 253
    Try((a, b) => a == (object)b, s1, s2);
#pragma warning restore 253
    Try((a, b) => (object)a == (object)b, s1, s2);
}
public void Try<T1, T2, T3>(Expression<Func<T1, T2, T3>> tryFunc, T1 in1, T2 in2)
{
    T3 out1;

    Try(tryFunc, e => { }, in1, in2, out out1);
}
public bool Try<T1, T2, T3>(Expression<Func<T1, T2, T3>> tryFunc, Action<Exception> catchFunc, T1 in1, T2 in2, out T3 out1)
{
    bool success = true;
    out1 = default(T3);

    try
    {
        out1 = tryFunc.Compile()(in1, in2);
        Debug.WriteLine("{0}: {1}", tryFunc.Body.ToString(), out1);
    }
    catch (Exception ex)
    {
        Debug.WriteLine("{0}: {1} - {2}", tryFunc.Body.ToString(), ex.GetType().ToString(), ex.Message);
        success = false;
        catchFunc(ex);
    }

    return success;
}

Output:

输出:

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

-- string.Equals --

Equals(a, b): True
Equals(Convert(a), b): True
Equals(a, Convert(b)): True
Equals(Convert(a), Convert(b)): True

-- object.Equals --

Equals(a, b): True
Equals(Convert(a), b): True
Equals(a, Convert(b)): True
Equals(Convert(a), Convert(b)): True

-- a.Equals(b) --

a.Equals(b): True
a.Equals(Convert(b)): True
Convert(a).Equals(b): True
Convert(a).Equals(Convert(b)): True

-- a == b --

(a == b): True
(Convert(a) == b): False
(a == Convert(b)): False
(Convert(a) == Convert(b)): False
--------------------

string a = null;
string b = null;

-- string.Equals --

Equals(a, b): True
Equals(Convert(a), b): True
Equals(a, Convert(b)): True
Equals(Convert(a), Convert(b)): True

-- object.Equals --

Equals(a, b): True
Equals(Convert(a), b): True
Equals(a, Convert(b)): True
Equals(Convert(a), Convert(b)): True

-- a.Equals(b) --

a.Equals(b): System.NullReferenceException - Object reference not set to an instance of an object.
a.Equals(Convert(b)): System.NullReferenceException - Object reference not set to an instance of an object.
Convert(a).Equals(b): System.NullReferenceException - Object reference not set to an instance of an object.
Convert(a).Equals(Convert(b)): System.NullReferenceException - Object reference not set to an instance of an object.

-- a == b --

(a == b): True
(Convert(a) == b): True
(a == Convert(b)): True
(Convert(a) == Convert(b)): True

#7


3  

It is clear that tvi.header is not a String. The == is an operator that is overloaded by String class, which means it will be working only if compiler knows that both side of the operator are String.

很明显,tvi。header不是字符串。==是一个由String类重载的操作符,这意味着只有当编译器知道操作符的两边是字符串时才会运行。

#8


-1  

An object is defined by an OBJECT_ID, which is unique. If A and B are objects and A == B is true, then they are the very same object, they have the same data and methods, but, this is also true:

对象由OBJECT_ID定义,它是惟一的。如果A和B是对象,A == B是真的,那么它们是相同的对象,它们有相同的数据和方法,但是,这也是正确的:

A.OBJECT_ID == B.OBJECT_ID

一个。OBJECT_ID = = B.OBJECT_ID

if A.Equals(B) is true, that means that the two objects are in the same state, but this doesn't mean that A is the very same as B.

如果A = (B)为真,那就意味着这两个对象处于同一状态,但这并不意味着A和B是一样的。

Strings are objects.

字符串是对象。

Note that the == and Equals operators are reflexive, simetric, tranzitive, so they are equivalentic relations (to use relational algebraic terms)

注意==和等于运算符是自反的,simetric, tranzitive,所以它们是相等的关系(使用关系代数术语)

What this means: If A, B and C are objects, then:

这意味着:如果A、B和C是对象,那么:

(1) A == A is always true; A.Equals(A) is always true (reflexivity)

(1)A == A始终为真;A. = (A)始终为真(自反性)

(2) if A == B then B == A; If A.Equals(B) then B.Equals(A) (simetry)

(2)如果A == B,则B == A;如果A等于(B)那么B = (A) (simetry)

(3) if A == B and B == C, then A == C; if A.Equals(B) and B.Equals(C) then A.Equals(C) (tranzitivity)

(3)if A == B和B == C,则A == C;如果a等于(B)和B = (C)那么a = (C) (tranzitivity)

Also, you can note that this is also true:

同样,你可以注意到这也是正确的:

(A == B) => (A.Equals(B)), but the inverse is not true.

(A == B) => (A = B),但逆是不成立的。

A B =>
0 0 1
0 1 1
1 0 0
1 1 1

Example of real life: Two Hamburgers of the same type have the same properties: they are objects of the Hamburger class, their properties are exactly the same, but they are different entities. If you buy these two Hamburgers and eat one, the other one won't be eaten. So, the difference between Equals and ==: You have hamburger1 and hamburger2. They are exactly in the same state (the same weight, the same temperature, the same taste), so hamburger1.Equals(hamburger2) is true. But hamburger1 == hamburger2 is false, because if the state of hamburger1 changes, the state of hamburger2 not necessarily change and vice versa.

现实生活的例子:两个相同类型的汉堡具有相同的属性:它们是汉堡类的对象,它们的属性完全相同,但它们是不同的实体。如果你买这两个汉堡,吃一个,另一个就不会被吃掉。所以,等号和==的区别是:你有hamburger1和hamburger2。它们完全处于相同的状态(相同的重量,相同的温度,相同的味道),所以hamburger1.Equals(hamburger2)是正确的。但是hamburger1 == hamburger2是假的,因为如果hamburger1的状态发生变化,hamburger2的状态不一定会改变,反之亦然。

If you and a friend get a Hamburger, which is yours and his in the same time, then you must decide to split the Hamburger into two parts, because you.getHamburger() == friend.getHamburger() is true and if this happens: friend.eatHamburger(), then your Hamburger will be eaten too.

如果你和一个朋友买了一个汉堡包,这是你的,同时也是他的,那么你必须决定把汉堡分成两份,因为你要吃汉堡()。

I could write other nuances about Equals and ==, but I'm getting hungry, so I have to go.

我可以写其他关于等号和==的细微差别,但是我饿了,所以我得走了。

Best regards, Lajos Arpad.

最好的问候,Lajos亚珥拔。