Question: 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?

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

![enter image description here](https://i.stack.imgur.com/cNjoP.png)
So this pseudocode runs:

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

```
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`.