52

So, when I was a comparative novice to the novice I am right now, I used to think that these two things were syntactic sugar for each other, i.e. that using one over the other was simply a personal preference. Over time, I'm come to find that these two are not the same thing, even in a default implementation (see this and this). To further confuse the matter, each can be overridden/overloaded separately to have completely different meanings.

Is this a good thing, what are the differences, and when/why should you use one over the other?

Csa77
  • 649
  • 13
  • 19
Matthew Scharley
  • 127,823
  • 52
  • 194
  • 222

9 Answers9

37
string x = "hello";
string y = String.Copy(x);
string z = "hello";

To test if x points to the same object as y:

(object)x == (object)y  // false
x.ReferenceEquals(y)    // false
x.ReferenceEquals(z)    // true (because x and z are both constants they
                        //       will point to the same location in memory)

To test if x has the same string value as y:

x == y        // true
x == z        // true
x.Equals(y)   // true
y == "hello"  // true

Note that this is different to Java. In Java the == operator is not overloaded so a common mistake in Java is:

y == "hello"  // false (y is not the same object as "hello")

For string comparison in Java you need to always use .equals()

y.equals("hello")  // true
molasses
  • 3,258
  • 6
  • 22
  • 22
  • 2
    For string operator == compares both string by contents .But that is not the case for other reference types – Vaysage Mar 29 '11 at 09:48
  • 1
    I want to underline what Vaysage just said: Using "string" as an example is **misleading** (or at least incomplete). It shows how strings work. But string is a **special case**. For this answer to be complete, contrast a `string` with: (a) a single character, (b) an array of characters, (c) a `struct` containing several character fields, (d) a `class` containing several character fields. Maybe would even need to show (e) a `class` containing a `struct` field or containing a `character array` field. Then do various assignments, show when the result is still `true`. – ToolmakerSteve May 08 '14 at 22:04
17

MSDN has clear and solid descriptions of both things.

object.Equals method

operator ==

Overloadable Operators

Guidelines for Overriding Equals() and Operator ==

Is this a good thing, what are the differences, and when/why should you use one over the other?

How can it be "good" or "bad" thing? One - method, another - operator. If reference equality is not sufficient, overload them, otherwise leave them as is. For primitive types they just work out of box.

aku
  • 122,288
  • 32
  • 173
  • 203
  • As someone getting into generics the differences can be vast when you are calling them on any type T blindly. – Matthew Scharley Sep 22 '08 at 00:26
  • 2
    "blindly" is a bad practice for anything. if you know the answer on your question, why asking? – aku Sep 22 '08 at 00:28
  • Even if I did know a concrete answer (which I don't), perhaps for the same reason people ask questions and answer themself? Also, how can you do anything else for a generic type T? If you start doing things like if (typeof(T) == typeof(int)), what's the point? – Matthew Scharley Sep 22 '08 at 00:31
  • As for my indignation, I encountered to many situations when I provide throughout answer, but person just want to show off and repeat my answer with some minor additions, thus wasting my time. If you really don't know the answer, I apologize. – aku Sep 22 '08 at 00:58
  • "Also, how can you do anything else" Sorry but I don't quite understand what you mean. Maybe you can ask concrete question about generics? – aku Sep 22 '08 at 00:59
  • Given say List, List shouldn't care what type T is, it shouldn't check anywhere what sort of object T is, it should only use Object's methods and expected results (excluding when there's restrictions on what T is). Or am I wrong here? – Matthew Scharley Sep 22 '08 at 01:27
  • List and List are two completely different classes. Each type can behave differently. In each case you should read description of Equal and == methods to understand how it works. If there are no notices, consider that only reference equality is used. – aku Sep 22 '08 at 01:37
  • If you want to discuss implementation of equality for generic collections, create new question. Comments is not a place for new questions. – aku Sep 22 '08 at 01:38
  • 2
    @aku: this answer would be handier if you **summarized** the essential difference(s) between the two operators. It isn't until the **fourth link (guidelines for overriding) that microsoft starts discussing the two equalities at the same time** -- which is necessary to respond to the question. (And I almost didn't bother clicking on the 4th link, because its title didn't sound promising, and the 3rd link seemed completely irrelevant.) – ToolmakerSteve May 08 '14 at 21:45
  • Actually, that 4th link doesn't help all that much either. It contrasts ReferenceEquals with Equals, but doesn't give guidelines for situations where Equals and "==" **should** give a different answer. As far as I can tell, someone designing a class should always make them behave the same. When would this not be the case? So far, I consider your answer to NOT address the question asked. All you've done is linked to microsoft documents, which **DO NOT** talk about what is different between the two. **You didn't answer the essential questions: When are these different? When prefer one?** – ToolmakerSteve May 08 '14 at 21:58
  • FYI, years later Microsoft finally gets it right, and says "Do ensure that Object.Equals and the equality operators have exactly the same semantics". http://msdn.microsoft.com/en-us/library/vstudio/7h9bszxx(v=vs.110).aspx That is, they **should** behave identically. The difference should be between `Object.ReferenceEquals` and `Object.Equals`; `==` **should** just be syntactic sugar for `Object.Equals`. That it isn't, is probably now viewed as one of their mistakes... – ToolmakerSteve May 08 '14 at 22:26
  • 8
    Why is this the accepted answer? It is an awful answer. – reach4thelasers Oct 26 '16 at 10:34
  • Need to describe each type individually--not just give links. – thecoolmacdude Apr 14 '17 at 13:32
  • It should be noted that if `x` is `null` (`Nothing` in vb.net), then `x.Equals()` will throw an exception. – mbomb007 Feb 12 '18 at 20:21
9

Microsoft says that class implementers should make == behave as similarly as possible to Equals:

DO ensure that Object.Equals and the equality operators have exactly the same semantics

from http://msdn.microsoft.com/en-us/library/vstudio/7h9bszxx(v=vs.110).aspx


If you want to be certain you are getting IDENTITY comparison (when comparing references), then use ReferenceEquals instead.

If a class implementor does not override ==, then static method is looked for, at compile time, in base classes. If this search reaches Object, then Object.== is used. For classes, this is same as ReferenceEquals.

If class documentation is uncertain as to whether a given class (from a vendor other than Microsoft presumably) implements == as Equals or ReferenceEquals (or it could in theory be different than both of those), I sometimes avoid ==. Instead, I use the less readable Equals(a, b) or ReferenceEquals(a, b), depending on which meaning I want.

OTOH, ps2goat makes a good point that using == avoids exception if first operand is null (because == is a static operator). This is an argument in favor of using ==.


Removed controversial commentary regarding ==


UPDATE A recent Microsoft doc quote, from .Net 4.7.2 retrieved Feb. 2019, shows they still intend the two to behave similarly:

Object.Equals Method

Some languages such as C# and Visual Basic support operator overloading. When a type overloads the equality operator, it must also override the Equals(Object) method to provide the same functionality. This is typically accomplished by writing the Equals(Object) method in terms of the overloaded equality operator, as in the following example.


NOTE: See other answers for the consequences of == being a static method vs Equals being an instance method. I'm not claiming behavior is identical; I'm observing that Microsoft recommends making the two as similar as possible.

ToolmakerSteve
  • 18,547
  • 14
  • 94
  • 196
  • 1
    I added another answer that may change your mind a bit (not that I mind your reasoning). Calling `.Equals()` on a null object (exception thrown) vs using a static operator that doesn't require either operand to be instantiated (no exception, works as expected). – ps2goat Aug 19 '15 at 22:31
  • Excellent answer. Thanks. Regarding your comment elsewhere on this page about being "puzzled as to why many of these answers link to that article" - it's StackOverflow: it's not about reading the full question and answering it, it's about how fast you can find something to nitpick in the question itself. Hence why the person criticising the question is at the top of the page and your answer which finally clarifies this mess in .NET is struggling to get votes. :-) – Derf Skren Sep 11 '15 at 04:54
  • Equals is semantic equality; two objects may be equal but have very subtle differences. == means the objects are fully interchangeable. The difference is very important when dealing with mutable objects, because you can change one object's state, and thus the result of Equals, at any time, but you can't change the result of ==. With immutable objects, the semantics are different because Equals and == never change. That is why overriding == is only recommended for immutable objects. This difference is critical, because when dealing with a mutable object, another thread or method can change it. – Andrew Rondeau Feb 20 '19 at 18:14
  • @AndrewRondeau - Microsoft's documented intent is that `==` operator behaves the same as `Equals`; hence the quote in my answer. OTOH, Microsoft does not enforce this. If you as a class designer choose to make the distinction you state, nothing will stop you. Can you describe a *specific* situation where you found this to be desirable? Also, re "you can't change the result of `==`". Yes you can; define an overload of operator `==` for your class. Often one implements `==` as `Equals`; indeed the Microsoft doc I reference *recommends* doing so. – ToolmakerSteve Feb 21 '19 at 21:26
  • @AndrewRondeau - I've updated my answer with a current quote that shows Microsoft still intends `==` and `Equals` to behave the same. (To the degree possible, given that one is an instance method, the other is a static method.) Do you have any alternative quote that shows otherwise? Not necessarily from Microsoft, but from any authoritative source re good programming practice in C#? [As you can see from my answer, I believe Microsoft's design is not good, so I would be interested in an alternative recommendation backed by details.] – ToolmakerSteve Feb 21 '19 at 21:48
  • @AndrewRondeau - I've added "If class implementor does not override `==` paragraph to cover the case you describe. But note that while this is the *default* behavior, it is up to the class implementor. [And I interpret Microsoft's quotes above as not recommending this.] Re "mutable objects", if a class implements `Equals`, I recommend not relying on `==` when you intend `ReferenceEquals`. Doing so could be misread by future maintainers of your software. If you are testing **identity equality**, then say so explicitly. (FWIW, in `java` what you said would always be true.) – ToolmakerSteve Feb 21 '19 at 23:11
  • @ToolmakerSteve: The exact example to follow is string. You can use == because two identical strings are fully interchangeable, even though they do not refer to the same exact object. This is because string is an immutable class. In contrast, StringBuilder does not override == because you can change the contents of one StringBuilder. This is because StringBuilder is mutable. – Andrew Rondeau Feb 22 '19 at 22:41
  • Honestly, I'm trying to find the spec I read about 10 years ago on the old MSDN. It made it rather clear that == was for situations where the objects were fully interchangeable. (Immutables, or situations where an eventing model propagates changes between objects.) I can't find that in Microsoft's newer documentation. The general rule of thumb, though, is that you should only overload == if the user of an object could interchange two objects where == is true. That rule doesn't apply to Equals(), though. – Andrew Rondeau Feb 22 '19 at 22:48
  • 1
    My answer at https://stackoverflow.com/a/54892972/1711103 has complete examples of when to use == versus Equals. – Andrew Rondeau Feb 26 '19 at 19:52
  • @AndrewRondeau - superb explanation. Also clarifies for me that when you commented on what "==" *should* mean, you were saying that from a mathematics standpoint, (not necessarily from Microsoft's mixed-messages on this topic)! I totally agree with your analysis - I've long considered this point a significant mistake on Microsoft's part. [I've followed OO languages longer than most people have been alive - soon I should be able to retire and contribute to tools that help improve OO programming techniques.] – ToolmakerSteve Feb 27 '19 at 19:53
6

I was going to post this as a comment on the accepted answer, but I think this deserves to be considered when determining which route to take.

dotnetfiddle: https://dotnetfiddle.net/gESLzO

Fiddle code:

    Object a = null;
    Object b = new Object();

    // Ex 1
    Console.WriteLine(a == b);
    // Ex 2
    Console.WriteLine(b == a);

    // Ex 3     
    Console.WriteLine(b.Equals(a));
    // Ex 4
    Console.WriteLine(a.Equals(b));

The first 3 WriteLine examples will work, but the fourth throws an exception. 1 and 2 use ==, which is a static method that does not require either object to be instantiated.

Example 3 works because b is instantiated.

Example 4 fails because a is null, and thus a method can not be called on a null object.

Because I try to code as lazily as possible, I use ==, especially when working with scenarios where either object (or both) can be null. If I didn't, I'd have to do a null check, first, before being able to call .Equals().

ps2goat
  • 8,067
  • 1
  • 35
  • 68
  • Note that this still occurs with strings, as well. And of course the operator could be overridden, but the essence of this answer is that operators are static and don't require non-null instances for either operand. – ps2goat Aug 19 '15 at 22:26
1

My understanding of the uses of both was this: use == for conceptual equality (in context, do these two arguments mean the same thing?), and .Equals for concrete equality (are these two arguments in actual fact the exact same object?).

Edit: Kevin Sheffield's linked article does a better job of explaining value vs. reference equality…

andrewdotnich
  • 16,195
  • 7
  • 38
  • 57
1

To answer this, we must describe the four kinds of object equivalence:

  1. Reference Equality, object.ReferenceEquals(a, b): The two variables point to the same exact object in RAM. (If this were C, both variables would have the same exact pointer.)

  2. Interchangeability, a == b: The two variables refer to objects that are completely interchangeable. Thus, when a == b, Func(a,b) and Func(b,a) do the same thing.

  3. Semantic Equality, object.Equals(a, b): At this exact moment in time, the two objects mean the same thing.

  4. Entity equality, a.Id == b.Id: The two objects refer to the same entity, such as a database row, but don’t have to have the same contents.

As a programmer, when working with an object of a known type, you need to understand the kind of equivalence that’s appropriate for your business logic at the specific moment of code that you’re in.

The simplest example about this is the string versus StringBuilder types. String overrides ==, StringBuilder does not:

var aaa1 = "aaa";
var aaa2 = $"{'a'}{'a'}{'a'}";
var bbb = "bbb";

// False because aaa1 and aaa2 are completely different objects with different locations in RAM
Console.WriteLine($"Object.ReferenceEquals(aaa1, aaa2): {Object.ReferenceEquals(aaa1, aaa2)}");

// True because aaa1 and aaa2 are completely interchangable
Console.WriteLine($"aaa1 == aaa2: {aaa1 == aaa2}");             // True
Console.WriteLine($"aaa1.Equals(aaa2): {aaa1.Equals(aaa2)}");   // True
Console.WriteLine($"aaa1 == bbb: {aaa1 == bbb}");               // False
Console.WriteLine($"aaa1.Equals(bbb): {aaa1.Equals(bbb)}");     // False

// Won't compile
// This is why string can override ==, you can not modify a string object once it is allocated
//aaa1[0] = 'd';

// aaaUpdated and aaa1 point to the same exact object in RAM
var aaaUpdated = aaa1;
Console.WriteLine($"Object.ReferenceEquals(aaa1, aaaUpdated): {Object.ReferenceEquals(aaa1, aaaUpdated)}"); // True

// aaaUpdated is a new string, aaa1 is unmodified
aaaUpdated += 'c';
Console.WriteLine($"Object.ReferenceEquals(aaa1, aaaUpdated): {Object.ReferenceEquals(aaa1, aaaUpdated)}"); // False

var aaaBuilder1 = new StringBuilder("aaa");
var aaaBuilder2 = new StringBuilder("aaa");

// False, because both string builders are different objects
Console.WriteLine($"Object.ReferenceEquals(aaaBuider1, aaaBuider2): {Object.ReferenceEquals(aaa1, aaa2)}");

// Even though both string builders have the same contents, they are not interchangable
// Thus, == is false
Console.WriteLine($"aaaBuider1 == aaaBuilder2: {aaaBuilder1 == aaaBuilder2}");

// But, because they both have "aaa" at this exact moment in time, Equals returns true
Console.WriteLine($"aaaBuider1.Equals(aaaBuilder2): {aaaBuilder1.Equals(aaaBuilder2)}");

// Modifying the contents of the string builders changes the strings, and thus
// Equals returns false
aaaBuilder1.Append('e');
aaaBuilder2.Append('f');
Console.WriteLine($"aaaBuider1.Equals(aaaBuilder2): {aaaBuilder1.Equals(aaaBuilder2)}");

To get into more details, we can work backwards, starting with entity equality. In the case of entity equality, properties of the entity may change over time, but the entity’s primary key never changes. This can be demonstrated with pseudocode:

// Hold the current user object in a variable
var originalUser = database.GetUser(123);

// Update the user’s name
database.UpdateUserName(123, user.Name + "son");

var updatedUser = database.GetUser(123);

Console.WriteLine(originalUser.Id == updatedUser.Id); // True, both objects refer to the same entity
Console.WriteLine(Object.Equals(originalUser, updatedUser); // False, the name property is different

Moving to semantic equality, the example changes slightly:

var originalUser = new User() { Name = "George" };
var updatedUser = new User() { Name = "George" };

Console.WriteLine(Object.Equals(originalUser, updatedUser); // True, the objects have the same contents
Console.WriteLine(originalUser == updatedUser); // User doesn’t define ==, False

updatedUser.Name = "Paul";

Console.WriteLine(Object.Equals(originalUser, updatedUser); // False, the name property is different

What about interchangeability? (overriding ==) That’s more complicated. Let’s build on the above example a bit:

var originalUser = new User() { Name = "George" };
var updatedUser = new User() { Name = "George" };
Console.WriteLine(Object.Equals(originalUser, updatedUser); // True, the objects have the same contents

// Does this change updatedUser? We don’t know
DoSomethingWith(updatedUser);

// Are the following equivalent?
// SomeMethod(originalUser, updatedUser);
// SomeMethod(updatedUser, originalUser);

In the above example, DoSomethingWithUser(updatedUser) might change updatedUser. Thus we can no longer guarantee that the originalUser and updatedUser objects are "Equals." This is why User does not override ==.

A good example for when to override == is with immutable objects. An immutable object is an object who’s publicly-visible state (properties) never change. The entire visible state must be set in the object’s constructor. (Thus, all properties are read-only.)

var originalImmutableUser = new ImmutableUser(name: "George");
var secondImmutableUser = new ImmutableUser(name: "George");

Console.WriteLine(Object.Equals(originalImmutableUser, secondImmutableUser); // True, the objects have the same contents
Console.WriteLine(originalImmutableUser == secondImmutableUser); // ImmutableUser defines ==, True

// Won’t compile because ImmutableUser has no setters
secondImmutableUser.Name = "Paul";

// But this does compile
var updatedImmutableUser = secondImmutableUser.SetName("Paul"); // Returns a copy of secondImmutableUser with Name changed to Paul.

Console.WriteLine(object.ReferenceEquals(updatedImmutableUser, secondImmutableUser)); // False, because updatedImmutableUser is a different object in a different location in RAM

// These two calls are equivalent because the internal state of an ImmutableUser can never change
DoSomethingWith(originalImmutableUser, secondImmutableUser);
DoSomethingWith(secondImmutableUser, originalImmutableUser);

Should you override == with a mutable object? (That is, an object who’s internal state can change?) Probably not. You would need to build a rather complicated event system to maintain interchangeability.

In general, I work with a lot of code that uses immutable objects, so I override == because it’s more readable than object.Equals. When I work with mutable objects, I don’t override == and rely on object.Equals. Its the programmer’s responsibility to know if the objects they are working with are mutable or not, because knowing if something’s state can change should influence how you design your code.

The default implementation of == is object.ReferenceEquals because, with mutable objects, interchangeability is only guaranteed when the variables point to the same exact object in RAM. Even if the objects have the same contents at a given point in time, (Equals returns true,) there is no guarantee that the objects will continue to be equal; thus the objects are not interchangeable. Thus, when working with a mutable object that does not override ==, the default implementation of == works, because if a == b, they are the same object, and SomeFunc(a, b) and SomeFunc(b, a) are exactly the same.

Furthermore, if a class does not define equivalence, (For example, think of a database connection, and open file handle, ect,) then the default implementation of == and Equals fall back to reference equality, because two variables of type database connection, open file handle, ect, are only equal if they are the exact instance of the database connection, open file handle, ect. Entity equality might make sense in business logic that needs to know that two different database connections refer to the same database, or that two different file handles refer to the same file on disk.

Now, for my soapbox moment. In my opinion, C# handles this topic in a confusing way. == should be for semantic equality, instead of the Equals method. There should be a different operator, like ===, for interchangeability, and potentially another operator, ====, for referential equality. This way, someone who's a novice, and / or writing CRUD applications, only needs to understand ==, and not the more nuanced details of interchangeability and referential equality.

Andrew Rondeau
  • 667
  • 7
  • 18
0

You may want to use .Equals as someone may come along at a later time and overload them for you class.

Ed S.
  • 122,712
  • 22
  • 185
  • 265
-1

Operator == and Equals() both are same while we are comparing values instead of references. Output of both are same see below example.

Example

    static void Main()
    {
        string x = " hello";
        string y = " hello";
        string z = string.Copy(x);
        if (x == y)
        {
            Console.WriteLine("== Operator");
        }
        if(x.Equals(y))
        {
            Console.WriteLine("Equals() Function Call");
        }
        if (x == z)
        {
            Console.WriteLine("== Operator while coping a string to another.");
        }
        if (x.Equals(y))
        {
            Console.WriteLine("Equals() Function Call while coping a string to another.");
        }
    }

Output:

  == Operator
  Equals() Function Call
  == Operator while coping a string to another.
  Equals() Function Call while coping a string to another.
Sonu Rajpoot
  • 485
  • 4
  • 6
-1

Two of the most often used types, String and Int32, implement both operator==() and Equals() as value equality (instead of reference equality). I think one can consider these two defining examples, so my conclusion is that both have identical meanings. If Microsoft states otherwise, I think they are intentionally causing confusion.

Dimitri C.
  • 21,861
  • 21
  • 85
  • 101
  • 1
    Within .net, the types that override the equality/inequality operators do so to impose value equality, but C# adds its own overload of the equality/inequality operators to check reference equality of objects which do not include a value-equality test. Personally, I dislike such a language design (vb.net uses the operators `Is` and `IsNot` to test reference equality; when applied to Framework types, `=` and `<>` will test value equality if they compile at all. There's nothing to prevent any type from overloading those operators to mean something totally different, however. – supercat Sep 23 '12 at 22:20