Mohammad Zargarani
Mohammad Zargarani

Reputation: 1422

What is the difference between == and Equals() for primitives in C#?

Consider this code:

int age = 25;
short newAge = 25;
Console.WriteLine(age == newAge);  //true
Console.WriteLine(newAge.Equals(age)); //false
Console.ReadLine();

Both int and short are primitive types, but a comparison with == returns true and a comparison with Equals returns false.

Why?

Upvotes: 182

Views: 19622

Answers (9)

SLaks
SLaks

Reputation: 888263

Short answer:

Equality is complicated.

Detailed answer:

Primitives types override the base object.Equals(object) and return true if the boxed object is of the same type and value. (Note that it will also work for nullable types; non-null nullable types always box to an instance of the underlying type.)

Since newAge is a short, its Equals(object) method only returns true if you pass a boxed short with the same value. You're passing a boxed int, so it returns false.

By contrast, the == operator is defined as taking two ints (or shorts or longs).
When you call it with an int and a short, the compiler will implicitly convert the short to int and compare the resulting ints by value.

Other ways to make it work

Primitive types also have their own Equals() method that accepts the same type.
If you write age.Equals(newAge), the compiler will select int.Equals(int) as the best overload and implicitly convert short to int. It will then return true, since this method simply compares the ints directly.

short also has a short.Equals(short) method, but int cannot be implicitly converted to short, so you aren't calling it.

You could force it to call this method with a cast:

Console.WriteLine(newAge.Equals((short)age)); // true

This will call short.Equals(short) directly, without boxing. If age is larger than 32767, it will throw an overflow exception.

You could also call the short.Equals(object) overload, but explicitly pass a boxed object so that it gets the same type:

Console.WriteLine(newAge.Equals((object)(short)age)); // true

Like the previous alternative, this will throw an overflow if it doesn't fit in a short. Unlike the previous solution, it will box the short into an object, wasting time and memory.

Source Code:

Here are both Equals() methods from the actual source code:

    public override bool Equals(Object obj) {
        if (!(obj is Int16)) {
            return false;
        }
        return m_value == ((Int16)obj).m_value;
    }

    public bool Equals(Int16 obj)
    {
        return m_value == obj;
    }

Further Reading:

See Eric Lippert.

Upvotes: 268

Zaheer Ahmed
Zaheer Ahmed

Reputation: 28588

== In Primitive

Console.WriteLine(age == newAge);          // true

In primitive comparison == operator behave quite obvious, In C# there are many == operator overload available.

  • string == string
  • int == int
  • uint == uint
  • long == long
  • many more

So in this case there is no implicit conversion from int to short but short to int is possible. So newAge is converted into int and comparison occurs which returns true as both holds same value. So it is equivalent to:

Console.WriteLine(age == (int)newAge);          // true

.Equals() in Primitive

Console.WriteLine(newAge.Equals(age));         //false

Here we need to see what Equals() method is, we calling Equals with a short type variable. So there are three possibilities:

  • Equals(object, object) // static method from object
  • Equals(object) // virtual method from object
  • Equals(short) // Implements IEquatable.Equals(short)

First type is not case here as number of arguments are different we calling with only one argument of type int. Third is also eliminated as mentioned above implicit conversion of int to short is not possible. So here Second type of Equals(object) is called. The short.Equals(object) is:

bool Equals(object z)
{
  return z is short && (short)z == this;
}

So here condition got tested z is short which is false as z is an int so it returns false.

Here is detailed article from Eric Lippert

Upvotes: 3

user2423959
user2423959

Reputation: 834

== is used for checking a equal condition, it can be considered as an operator(boolean operator), just to compare 2 things and here the data type doesn't matter as there would be a type casting done and Equals is also used for checking equals condition, but in this case the data types should be same. N Equals is a method not an operator.

Below is a small example taken from the one you provided and this will clarify difference in brief,.

int x=1;
short y=1;
x==y;//true
y.Equals(x);//false

in the above example, X and Y have same values i.e. 1, and when we use ==, it will return true, as in case of ==, the short type is converted to int by the compiler and the result is given.

and when we use Equals, the comparing is done, but the type casting is not done by compiler, so false is returned.

Guys, please let me know if I'm wrong.

Upvotes: 10

Wagner DosAnjos
Wagner DosAnjos

Reputation: 6374

For value types, .Equals requires the two objects to be of the same type and have the same value, while == just tests if the two values are the same.

Object.Equals
http://msdn.microsoft.com/en-us/library/bsc2ak47(v=vs.110).aspx

Upvotes: 12

user1968030
user1968030

Reputation:

When you pass int to short's Equals you pass object:

enter image description here So this pseudocode runs:

return obj is short && this == (short)obj;

Upvotes: 12

Simon Whitehead
Simon Whitehead

Reputation: 65107

Because there is no overload for short.Equals that accepts an int. Therefore, this is called:

public override bool Equals(object obj)
{
    return obj is short && this == (short)obj;
}

obj is not a short.. therefore, it is false.

Upvotes: 55

user276648
user276648

Reputation: 6393

What you need to realize is that doing == will always end up calling a method. The question is whether calling == and Equals ends up calling/doing the same things.

With reference types, == will always 1st check whether the references are the same (Object.ReferenceEquals). Equals on the other hand can be overridden and may check whether some values are equal.

EDIT: to answer svick and add on SLaks comment, here is some IL code

int i1 = 0x22; // ldc.i4.s ie pushes an int32 on the stack
int i2 = 0x33; // ldc.i4.s 
short s1 = 0x11; // ldc.i4.s (same as for int32)
short s2 = 0x22; // ldc.i4.s 

s1 == i1 // ceq
i1 == s1 // ceq
i1 == i2 // ceq
s1 == s2 // ceq
// no difference between int and short for those 4 cases,
// anyway the shorts are pushed as integers.

i1.Equals(i2) // calls System.Int32.Equals
s1.Equals(s2) // calls System.Int16.Equals
i1.Equals(s1) // calls System.Int32.Equals: s1 is considered as an integer
// - again it was pushed as such on the stack)
s1.Equals(i1) // boxes the int32 then calls System.Int16.Equals
// - int16 has 2 Equals methods: one for in16 and one for Object.
// Casting an int32 into an int16 is not safe, so the Object overload
// must be used instead.

Upvotes: 4

supercat
supercat

Reputation: 81347

In many contexts where a method or operator argument is not of the required type, the C# compiler will attempt to perform an implicit type conversion. If the compiler can make all arguments satisfy their operators and methods by adding implicit conversions, it will do so without complaint, even though in some cases (especially with equality tests!) the results may be surprising.

Further, each value type such as int or short actually describes both a kind of value and a kind of object(*). Implicit conversions exist to convert values to other kinds of values, and to convert any kind of value to its corresponding kind of object, but the different kinds of objects are not implicitly convertible to each other.

If one uses the == operator to compare a short and an int, the short will be implicitly converted to an int. If its numerical value was equal to that of the int, the int to which it was converted will equal the int to which it is compared. If one attempts to use the Equals method on the short to compare it with an int, however, the only implicit conversion which would satisfy an overload of the Equals method would be the conversion to the object type corresponding to int. When the short is asked whether it matches the passed-in object, it will observe that the object in question is an int rather than a short and thus conclude that it cannot possibly be equal.

In general, although the compiler won't complain about it, one should avoid comparing things which are not of the same type; if one is interested in whether conversion of things to a common form would give the same result, one should perform such conversion explicitly. Consider, for example,

int i = 16777217;
float f = 16777216.0f;

Console.WriteLine("{0}", i==f);

There are three ways in which one might want to compare an int to a float. One might want to know:

  1. Does the closest possible float value to the int match the float?
  2. Does the whole-number part of the float match the int?
  3. Do the int and float represent the same numerical value.

If one tries to compare an int and float directly, the compiled code will answer the first question; whether that's what the programmer intended, however, will be far from obvious. Changing the comparison to (float)i == f would make it clear that the first meaning was intended, or (double)i == (double)f would cause the code to answer the third question (and make it clear that's what was intended).

(*) Even if the C# spec regards a value of type e.g. System.Int32 as being an object of type System.Int32, such a view is contradicted by the requirement that a code run on a platform whose spec regards values and objects as inhabiting different universes. Further, if T is a reference type, and x is a T, then a reference of type T should be able to refer to x. Thus, if a variable v of type Int32 holds an Object, a reference of type Object should be able to hold a reference to v or its contents. In fact, a reference of type Object would be able to point to an object holding data copied from v, but not to v itself nor to its contents. That would suggest that neither v nor its contents is really an Object.

Upvotes: 6

Sugat Mankar
Sugat Mankar

Reputation: 478

Equals() is a method of System.Object Class
Syntax : Public virtual bool Equals()
Recommendation if we want to compare state of two objects then we should use Equals() method

as stated above answers == operators compare the values are same.

Please don't get confused with ReferenceEqual

Reference Equals()
Syntax : public static bool ReferenceEquals()
It determine whether the specified objects instance are of the same instance

Upvotes: 6

Related Questions