简体   繁体   English

C# == 和 Equals() 之间的区别

[英]C# difference between == and Equals()

I have a condition in a silverlight application that compares 2 strings, for some reason when I use == it returns false while .Equals() returns true .我在比较 2 个字符串的 silverlight 应用程序中有一个条件,由于某种原因,当我使用==时它返回false.Equals()返回true

Here is the code:这是代码:

if (((ListBoxItem)lstBaseMenu.SelectedItem).Content.Equals("Energy Attack"))
{
    // Execute code
}

if (((ListBoxItem)lstBaseMenu.SelectedItem).Content == "Energy Attack")
{
    // Execute code
}

Any reason as to why this is happening?为什么会发生这种情况?

When == is used on an expression of type object , it'll resolve to System.Object.ReferenceEquals .==用于object类型的表达式时,它将解析为System.Object.ReferenceEquals

Equals is just a virtual method and behaves as such, so the overridden version will be used (which, for string type compares the contents).Equals只是一个virtual方法并且行为如此,因此将使用覆盖的版本(对于string类型比较内容)。

When comparing an object reference to a string (even if the object reference refers to a string), the special behavior of the == operator specific to the string class is ignored.将对象引用与字符串进行比较时(即使对象引用引用字符串),特定于字符串类的==运算符的特殊行为将被忽略。

Normally (when not dealing with strings, that is), Equals compares values , while == compares object references .通常(即不处理字符串时), Equals比较,而==比较对象引用 If two objects you are comparing are referring to the same exact instance of an object, then both will return true, but if one has the same content and came from a different source (is a separate instance with the same data), only Equals will return true.如果您比较的两个对象指的是一个对象的同一个实例,则两者都将返回 true,但如果一个具有相同的内容并且来自不同的源(是具有相同数据的单独实例),则只有 Equals返回真。 However, as noted in the comments, string is a special case because it overrides the == operator so that when dealing purely with string references (and not object references), only the values are compared even if they are separate instances.但是,正如注释中所指出的,字符串是一种特殊情况,因为它覆盖了==运算符,因此在纯粹处理字符串引用(而不是对象引用)时,即使它们是单独的实例,也只会比较值。 The following code illustrates the subtle differences in behaviors:以下代码说明了行为的细微差别:

string s1 = "test";
string s2 = "test";
string s3 = "test1".Substring(0, 4);
object s4 = s3;

Console.WriteLine($"{object.ReferenceEquals(s1, s2)} {s1 == s2} {s1.Equals(s2)}");
Console.WriteLine($"{object.ReferenceEquals(s1, s3)} {s1 == s3} {s1.Equals(s3)}");
Console.WriteLine($"{object.ReferenceEquals(s1, s4)} {s1 == s4} {s1.Equals(s4)}");

The output is:输出是:

True True True
False True True
False False True

== and .Equals are both dependent upon the behavior defined in the actual type and the actual type at the call site. ==.Equals都取决于实际类型中定义的行为和调用站点的实际类型。 Both are just methods / operators which can be overridden on any type and given any behavior the author so desires.两者都只是方法/运算符,可以在任何类型上覆盖并给出作者想要的任何行为。 In my experience, I find it's common for people to implement .Equals on an object but neglect to implement operator == .根据我的经验,我发现人们在对象上实现.Equals而忽略实现 operator ==是很常见的。 This means that .Equals will actually measure the equality of the values while == will measure whether or not they are the same reference.这意味着.Equals将实际测量值的相等性,而==将测量它们是否是相同的引用。

When I'm working with a new type whose definition is in flux or writing generic algorithms, I find the best practice is the following当我使用定义不断变化的新类型或编写泛型算法时,我发现最佳实践如下

  • If I want to compare references in C#, I use Object.ReferenceEquals directly (not needed in the generic case)如果我想比较 C# 中的引用,我直接使用Object.ReferenceEquals (一般情况下不需要)
  • If I want to compare values I use EqualityComparer<T>.Default如果我想比较值,我使用EqualityComparer<T>.Default

In some cases when I feel the usage of == is ambiguous I will explicitly use Object.Reference equals in the code to remove the ambiguity.在某些情况下,当我觉得==的用法有歧义时,我会在代码中明确使用Object.Reference equals 来消除歧义。

Eric Lippert recently did a blog post on the subject of why there are 2 methods of equality in the CLR. Eric Lippert 最近发表了一篇关于为什么 CLR 中有 2 种相等方法的主题的博客文章。 It's worth the read值得一读

== Operator == 运算符

  1. If operands are Value Types and their values are equal, it returns true else false.如果操作数是值类型并且它们的相等,则返回 true 否则返回 false。
  2. If operands are Reference Types with exception of string and both refer to the same instance (same object), it returns true else false.如果操作数是除字符串之外的引用类型并且都引用同一个实例(同一个对象),则返回 true 否则返回 false。
  3. If operands are string type and their values are equal, it returns true else false.如果操作数是字符串类型并且它们的相等,则返回真,否则返回假。

.Equals 。等于

  1. If operands are Reference Types , it performs Reference Equality that is if both refer to the same instance (same object), it returns true else false.如果操作数是引用类型,则执行引用相等,即如果两者都引用同一个实例(同一个对象),则返回 true,否则返回 false。
  2. If Operands are Value Types then unlike == operator it checks for their type first and if their types are same it performs == operator else it returns false.如果操作数是值类型,则与 == 运算符不同,它首先检查它们的类型,如果它们的类型相同,则执行 == 运算符,否则返回 false。

As far as I understand it the answer is simple:据我了解,答案很简单:

  1. == compares object references. ==比较对象引用。
  2. .Equals compares object content. .Equals比较对象内容。
  3. String datatypes always act like content comparison. String数据类型总是像内容比较一样。

I hope I'm correct and that it answered your question.我希望我是正确的,它回答了你的问题。

Firstly, there is a difference.首先,有区别的。 For numbers对于数字

> 2 == 2.0
True

> 2.Equals(2.0)
False

And for strings而对于字符串

> string x = null;
> x == null
True

> x.Equals(null)
NullReferenceException

In both cases, == behaves more usefully than .Equals在这两种情况下, ==.Equals

I would add that if you cast your object to a string then it will work correctly.我要补充一点,如果您将对象转换为字符串,那么它将正常工作。 This is why the compiler will give you a warning saying:这就是为什么编译器会给你一个警告说:

Possible unintended reference comparison;可能的意外参考比较; to get a value comparison, cast the left hand side to type 'string'要进行值比较,请将左侧强制转换为“字符串”

Because the static version of the .Equal method was not mentioned so far, I would like to add this here to summarize and to compare the 3 variations.因为到目前为止还没有提到.Equal方法的静态版本,我想在这里添加这个来总结和比较 3 个变体。

MyString.Equals("Somestring"))          //Method 1
MyString == "Somestring"                //Method 2
String.Equals("Somestring", MyString);  //Method 3 (static String.Equals method) - better

where MyString is a variable that comes from somewhere else in the code.其中MyString是来自代码中其他地方的变量。

Background info and to summerize:背景信息和总结:

In Java using == to compare strings should not be used.在 Java 中,不应使用==来比较字符串。 I mention this in case you need to use both languages and also to let you know that using == can also be replaced with something better in C#.如果您需要同时使用这两种语言,我会提到这一点,并且让您知道使用==也可以用 C# 中更好的东西代替。

In C# there's no practical difference for comparing strings using Method 1 or Method 2 as long as both are of type string.在 C# 中,使用方法 1 或方法 2 比较字符串没有实际区别,只要它们都是字符串类型。 However, if one is null, one is of another type (like an integer), or one represents an object that has a different reference, then, as the initial question shows, you may experience that comparing the content for equality may not return what you expect.但是,如果一个为空,一个是另一种类型(如整数),或者一个表示具有不同引用的对象,那么,如最初的问题所示,您可能会遇到比较内容是否相等可能不会返回什么你期待。

Suggested solution:建议的解决方案:

Because using == is not exactly the same as using .Equals when comparing things, you can use the static String.Equals method instead.因为在比较事物时使用==与使用.Equals并不完全相同,所以您可以改用静态 String.Equals方法。 This way, if the two sides are not the same type you will still compare the content and if one is null, you will avoid the exception.这样,如果两侧的类型不同,您仍然会比较内容,如果一个为空,您将避免异常。

   bool areEqual = String.Equals("Somestring", MyString);  

It is a little more to write, but in my opinion, safer to use.写的多一点,但在我看来,使用起来更安全。

Here is some info copied from Microsoft:以下是从 Microsoft 复制的一些信息:

public static bool Equals (string a, string b);

Parameters参数

a String a字符串

The first string to compare, or null .要比较的第一个字符串,或null

b String b字符串

The second string to compare, or null .要比较的第二个字符串,或null

Returns Boolean返回Boolean

true if the value of a is the same as the value of b ;如果a的值与b的值相同,则为true otherwise, false .否则为false If both a and b are null , the method returns true .如果ab都为null ,则该方法返回true

Just as an addition to the already good answers: This behaviour is NOT limited to Strings or comparing different numbertypes.作为对已经很好的答案的补充:此行为不仅限于字符串或比较不同的数字类型。 Even if both elements are of type object of the same underlying type.即使两个元素都是相同基础类型的 object 类型。 "==" won't work. “==”不起作用。

The following screenshot shows the results of comparing two object {int} - values以下屏幕截图显示了比较两个对象 {int} - 值的结果

来自 VS2017 的示例

Adding one more point to the answer.给答案补充一点。

.EqualsTo() method gives you provision to compare against culture and case sensitive. .EqualsTo()方法为您提供了与文化和区分大小写进行比较的条件。

There is another dimension to an earlier answer by @BlueMonkMN. @BlueMonkMN 的早期答案还有另一个维度。 The additional dimension is that the answer to the @Drahcir's title question as it is stated also depends on how we arrived at the string value.额外的维度是,@Drahcir 标题问题的答案也取决于我们如何获得string值。 To illustrate:为了显示:

string s1 = "test";
string s2 = "test";
string s3 = "test1".Substring(0, 4);
object s4 = s3;
string s5 = "te" + "st";
object s6 = s5;
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s2), s1 == s2, s1.Equals(s2));

Console.WriteLine("\n  Case1 - A method changes the value:");
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s3), s1 == s3, s1.Equals(s3));
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s4), s1 == s4, s1.Equals(s4));

Console.WriteLine("\n  Case2 - Having only literals allows to arrive at a literal:");
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s5), s1 == s5, s1.Equals(s5));
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s6), s1 == s6, s1.Equals(s6));

The output is:输出是:

True True True

  Case1 - A method changes the value:
False True True
False False True

  Case2 - Having only literals allows to arrive at a literal:
True True True
True True True

I am a bit confused here.我在这里有点困惑。 If the runtime type of Content is of type string, then both == and Equals should return true.如果 Content 的运行时类型是字符串类型,则 == 和 Equals 都应返回 true。 However, since this does not appear to be the case, then runtime type of Content is not string and calling Equals on it is doing a referential equality and this explains why Equals("Energy Attack") fails.但是,由于情况似乎并非如此,因此内容的运行时类型不是字符串,并且对其调用 Equals 是在执行引用相等,这解释了 Equals("Energy Attack") 失败的原因。 However, in the second case, the decision as to which overloaded == static operator should be called is made at compile time and this decision appears to be ==(string,string).然而,在第二种情况下,关于应该调用哪个重载 == 静态运算符的决定是在编译时做出的,这个决定似乎是 ==(string,string)。 this suggests to me that Content provides an implicit conversion to string.这向我表明 Content 提供了到字符串的隐式转换。

Really great answers and examples!真的很棒的答案和例子!

I would just like to add the fundamental difference between the two,我只想补充两者之间的根本区别,

Operators such as == are not polymorphic, while Equals is ==等运算符不是多态的,而Equals是多态的

With that concept in mind, if you work out any example (by looking at left hand and right hand reference type, and checking/knowing if the type actually has == operator overloaded and Equals being overriden) you are certain to get the right answer.考虑到这个概念,如果您计算出任何示例(通过查看左手和右手引用类型,并检查/知道该类型是否实际具有 == 运算符重载和 Equals 被覆盖),您一定会得到正确的答案.

This is due to value equality (equal method) and referential equality(== operator), as the equal method checks the values while the same == is checked the reference.这是由于值相等(相等方法)和引用相等(== 运算符),因为相等方法检查值,而相同的 == 检查引用。

== operator overriding code available inside the string class on https://referencesource.microsoft.com/ == 运算符覆盖代码在https://referencesource.microsoft.com/上的字符串类中可用

so now it's easier to understand, the equal method also has 2 implementations one from the string class itself and one from the object class.所以现在更容易理解了,equal 方法也有 2 个实现,一个来自字符串类本身,一个来自对象类。 its impact on performance as well I also run some basic code and try to understand the benchmarks.它对性能的影响以及我还运行了一些基本代码并尝试了解基准测试。

I am sharing the results below Please correct or advise if I am wrong somewhere.我在下面分享结果请纠正或建议我是否在某处错了。 there are 3 cases and I have run the same code for all the cases and this is the result.有 3 个案例,我为所有案例运行了相同的代码,这就是结果。

case 1: here I am using string.案例 1:这里我使用的是字符串。 equal method for comparing 2 strings and both the string have the same values.用于比较 2 个字符串且两个字符串具有相同值的 equal 方法。 string.equals(a,b) string.equals(a,b)

1st run:5608195 ticks第一次运行:5608195 滴答

2nd run:5529387 ticks第二次运行:5529387 滴答

3rd run:5622569 ticks第三次运行:5622569 滴答声

total ticks: 16760151总滴答数:16760151

case 2: here I am using string.情况 2:这里我使用的是字符串。 equal() method(overloaded one) for comparing 2 strings and both the string have the same values.用于比较 2 个字符串并且两个字符串具有相同值的 equal() 方法(重载一个)。 a.equals(b) a.等于(b)

1st run: 6738583 ticks第一次运行:6738583 个滴答声

2nd run: 6452927 ticks第二次运行:6452927 个滴答声

3rd run: 7168897 ticks第三次运行:7168897 个滴答声

total ticks=20360407总滴答数=20360407

case 3: here I am using the == operator for comparing 2 strings and both the string have the same values.情况 3:这里我使用 == 运算符来比较 2 个字符串,并且两个字符串都具有相同的值。 a==b a==b

1st run: 6652151 ticks第一次运行:6652151 个滴答声

2nd run: 7514300 ticks第二次运行:7514300 滴答

3rd run: 7634606 ticks第三次运行:7634606 滴答

total ticks=21801057总滴答数=21801057

class Program
{
    private static int count;
    static string a = "abcdef";
    static string b = "abcdef";
    static void Main(string[] args)
    {            

        for (int j = 1; j <= 3; j++)
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            for (int i = 1; i <= 1000; i++)
            {
                checkString();
            }
            sw.Stop();
            Console.WriteLine(sw.ElapsedTicks);
        }
        Console.ReadLine();

    }
    public static void checkString()
    {
        for (int i = 1; i <= 100000; i++)
        {
            if (a==b)
                count++;
        }
    }
}

The == token in C# is used for two different equality-check operators. C# 中的==标记用于两个不同的相等检查运算符。 When the compiler encounters that token, it will check whether either of the types being compared has implemented an equality-operator overload for either the specific combination types being compared(*), or for a combination of types to which both types can be converted.当编译器遇到该标记时,它将检查被比较的任一类型是否已为被比较的特定组合类型 (*) 或两种类型都可以转换为的类型组合实现了相等运算符重载。 If the compiler finds such an overload it will use it.如果编译器发现这样的重载,它将使用它。 Otherwise, if the two types are both reference types and they are not unrelated classes (either may be an interface, or they may be related classes), the compiler will regard == as a reference-comparison operator.否则,如果这两种类型都是引用类型并且它们不是不相关的类(可能是接口,也可能是相关类),编译器会将==视为引用比较运算符。 If neither condition applies, compilation will fail.如果两个条件都不适用,编译将失败。

Note that some other languages use separate tokens for the two equality-check operators.请注意,其他一些语言对两个相等检查运算符使用单独的标记。 In VB.NET, for example, the = token is used within expressions solely for the overloadable equality-check operator, and Is is used as a reference-test or null-test operator.例如,在 VB.NET 中, =标记在表达式中仅用于可重载的相等检查运算符,而Is用作引用测试或空测试运算符。 An to use = on a type which does not override the equality-check operator will fail, as will attempting to use Is for any purpose other than testing reference equality or nullity.在不覆盖相等检查运算符的类型上使用=将失败,尝试将Is用于测试引用相等性或无效性以外的任何目的也会失败。

(*)Types generally only overload equality for comparison with themselves, but it may be useful for types to overload the equality operator for comparison with other particular types; (*) 类型通常只重载相等以与自身进行比较,但对于类型来说,重载相等运算符以与其他特定类型进行比较可能很有用; for example, int could have (and IMHO should have but didn't) defined an equality operators for comparison with float , so that 16777217 would not report itself equal to 16777216f.例如, int可以(恕我直言应该有但没有)定义了一个相等的运算符来与float进行比较,这样 16777217 就不会报告自己等于 16777216f。 As it is, since no such operator is defined, C# will promote the int to float , rounding it to 16777216f before the equality-check operator sees it;实际上,由于没有定义这样的运算符,C# 会将int提升为float ,在相等检查运算符看到它之前将其四舍五入为 16777216f ; that operator then sees two equal floating-point numbers and reports them as equal, unaware of the rounding that took place.该运算符然后看到两个相等的浮点数并将它们报告为相等,不知道发生的舍入。

Whether Equals() and == are the same depends on the implementation . Equals()==是否相同取决于实现 Because C# allows users to set different behaviors for Equals() and == respectively.因为 C# 允许用户分别为Equals()==设置不同的行为。

    class CompareTest
    {
        public readonly int val;

        public CompareTest(int val)
        {
            this.val = val;
        }

        public override bool Equals(object obj)
        {
            return obj is CompareTest test && this.val == test.val;
        }

        public override int GetHashCode()
        {
            return val;
        }

        public static bool operator == (CompareTest a, object b)
        {
            return Equals(a, b);
        }

        public static bool operator != (CompareTest a, object b)
        {
            return !(a == b);
        }
    }

In this example, I made Equals() and == have the same behavior.在此示例中,我使Equals()==具有相同的行为。 But what if I make them different?但是如果我让它们不同呢? For example:例如:

        public static bool operator == (CompareTest a, object b)
        {
            return false;
        }

Equals() works normally but == will never works. Equals()正常工作,但==永远不会工作。

Furthermore, although I made them have the same behavior, but there is still one difference: which == function will be called depends on the left value:此外,虽然我使它们具有相同的行为,但仍有一个区别:将调用哪个== function 取决于左侧的值:

        Compare Test a = new CompareTest(1);
        object b = new CompareTest(1);
        CompareTest c = new CompareTest(1);
        Debug.Log("AB " + (a == b)); // true
        Debug.Log("BA " + (b == a)); // false! because it calls object's == function 
        Debug.Log("AC " + (a == c)); // true
        Debug.Log("CA " + (c == a)); // true

When we create any object there are two parts to the object one is the content and the other is reference to that content.当我们创建任何对象时,对象有两个部分,一个是内容,另一个是对该内容的引用。 == compares both content and reference; ==比较内容和参考; equals() compares only content equals()只比较内容

http://www.codeproject.com/Articles/584128/What-is-the-difference-between-equalsequals-and-Eq http://www.codeproject.com/Articles/584128/What-is-the-difference-between-equalsequals-and-Eq

Note that there are two different types of equality in C#请注意,C# 中有两种不同类型的相等性

1- Value Equality (For value types like int, DateTime and struct) 1- Value Equality (对于 int、DateTime 和 struct 等值类型)

2- Reference Equality (For objects) 2- Reference Equality (对于对象)

There are two basic standard protocols for implement equality checks.有两种基本的标准协议用于实现相等性检查。

1- The == and != operators. 1- ==!=运算符。

2- The virtual Equals method. 2- virtual Equals方法。

The == and != are statically resolve, which means C# will make a compile-time decision as to which type will perform the comparison. == 和 != 是静态解析的,这意味着 C# 将在编译时决定哪种类型将执行比较。

For instance the value-type例如value-type

 int x = 50;
 int y = 50;
 Console.WriteLine (x == y); // True

but for reference type但对于reference type

 object x = 50;
 object y = 50;
 Console.WriteLine (x == y); // False 

The Equals() originally resoled at runtime according to operand actual type. Equals()最初在运行时根据操作数的实际类型进行解析。

For instance, in the following example, at runtime, it will be decided that the Equals() will apply on int values, the result is true .例如,在以下示例中,在运行时,将决定Equals()将应用于 int 值,结果为true

object x = 5;
object y = 5;
Console.WriteLine (x.Equals (y)); // True

However, for a reference type, it will use a reference equality check.但是,对于引用类型,它将使用引用相等性检查。

MyObject x = new MyObject();
MyObject y = x;
Console.WriteLine (x.Equals (y)); // True

Note that Equals() uses structural comparison for struct , which means it calls Equals on each field of a struct.请注意, Equals()struct使用结构比较,这意味着它在结构的每个字段上调用 ​​Equals。

== ==

The == operator can be used to compare two variables of any kind, and it simply compares the bits . == 运算符可用于比较任何类型的两个变量,它只是比较位

int a = 3;
byte b = 3;
if (a == b) { // true }

Note : there are more zeroes on the left side of the int but we don't care about that here.注意:int 的左侧有更多的零,但我们在这里不关心。

int a (00000011) == byte b (00000011) int a (00000011) == 字节 b (00000011)

Remember == operator cares only about the pattern of the bits in the variable.记住 == 运算符只关心变量中位的模式。

Use == If two references (primitives) refers to the same object on the heap.使用 == 如果两个引用(原语)指向堆上的同一个对象。

Rules are same whether the variable is a reference or primitive.无论变量是引用还是原始变量,规则都是相同的。

Foo a = new Foo();
Foo b = new Foo();
Foo c = a;

if (a == b) { // false }
if (a == c) { // true }
if (b == c) { // false }

a == c is true a == b is false a == c 为真 a == b 为假

the bit pattern are the same for a and c, so they are equal using ==. a 和 c 的位模式相同,因此使用 == 时它们相等。

Equal():平等的():

Use the equals() method to see if two different objects are equal .使用 equals() 方法查看两个不同的对象是否相等

Such as two different String objects that both represent the characters in "Jane"例如两个不同的 String 对象,它们都代表“Jane”中的字符

The only difference between Equal and == is on object type comparison. Equal 和 == 之间的唯一区别在于对象类型比较。 in other cases, such as reference types and value types, they are almost the same(either both are bit-wise equality or both are reference equality).在其他情况下,例如引用类型和值类型,它们几乎相同(要么都是按位相等,要么都是引用相等)。

object: Equals: bit-wise equality ==: reference equality object: Equals: 按位相等 ==: 引用相等

string: (equals and == are the same for string, but if one of string changed to object, then comparison result will be different) Equals: bit-wise equality == : bit-wise equality字符串:(字符串的equals和==是一样的,但是如果字符串中的一个变成了对象,那么比较结果就会不同) Equals: bit-wisequality == : bit-wisequality

See here for more explanation.有关更多解释,请参见此处

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM