Reputation: 13820
In C# Why does Double
override ==
but Int32
does not, and what is the effect?
I look at the msdn library.
I see this link about double which doesn't say much here (though I understand double is a shorthand for the Double
object).. It doesn't show methods for example..
but this link on System.Double
does mention what I'm looking for here
It shows the Equality operator taking doubles, so overloaded.
Image For Double
in MSDN, then after Methods (before listing Fields), it shows Operators, and it shows equality operator is overridden
and I can click Equality under "Operators" and it says
public static bool operator ==(
double left,
double right
)
Whereas when I look at System.Int32
Image For Int32
in MSDN is below
See in that image, (the page for System.Int32
) it looks like ==
is not overridden.
Why, and what are the ramifications of this?
Upvotes: 10
Views: 481
Reputation: 9089
Int32
seems to be very special in terms of .NET. The functionality that is missing from the source code is more than likely baked into core of the system.
You cannot compare structs/value-types with ==
, >
, etc. without declaring those operators inside the struct. Because Int32
is missing these I came to the conclusion above.
Doing a simple test and dumping the IL, they are doing the exact same comparison and no CompareTo
or Equals
is getting called (which I thought actually happened. I learned something!).
public void TestInts()
{
var x = 1;
var y = 2;
var equals = x == y;
}
.method public hidebysig
instance void TestInts () cil managed
{
// Method begins at RVA 0x2094
// Code size 11 (0xb)
.maxstack 2
.locals init (
[0] int32 x,
[1] int32 y,
[2] bool equals
)
IL_0000: nop
IL_0001: ldc.i4.1
IL_0002: stloc.0
IL_0003: ldc.i4.2
IL_0004: stloc.1
IL_0005: ldloc.0
IL_0006: ldloc.1
IL_0007: ceq
IL_0009: stloc.2
IL_000a: ret
}
public void TestDoubles()
{
var x = 1.7d;
var y = 1.5d;
var equals = x == y;
}
.method public hidebysig
instance void TestDoubles () cil managed
{
// Method begins at RVA 0x20ac
// Code size 27 (0x1b)
.maxstack 2
.locals init (
[0] float64 x,
[1] float64 y,
[2] bool equals
)
IL_0000: nop
IL_0001: ldc.r8 1.7
IL_000a: stloc.0
IL_000b: ldc.r8 1.5
IL_0014: stloc.1
IL_0015: ldloc.0
IL_0016: ldloc.1
IL_0017: ceq
IL_0019: stloc.2
IL_001a: ret
}
The above IL just has the standard ceq
opcode called for both cases. By .NET standards, Int32
should have the comparison operators declared in the source code, but it does not.
EDIT: It appears as though all whole-number value-types are like this. Single, Double, Decimal all have the operators specified in the source code. Int16, Int32, Int64, Byte, do not.
Upvotes: 1
Reputation: 6050
One possible reason is because of the Double.NaN.
For the == operator: MSDN says: If two Double.NaN values are tested for equality by using the equality operator(==), the result is false; two Double.NaN values are not considered equal. If they are tested for equality by calling the Equals method, the result is true. When you want to determine whether the value of a Double is not a number (NaN), an alternative is to call the IsNaN method.
So the == operator and the Equals methods of Double have different behavior regards to Double.NaN, I think this why == is override for double. As for int, there's no such special case.
The code to demo the differences:
using System;
public class Example
{
public static void Main()
{
Console.WriteLine("NaN == NaN: {0}", Double.NaN == Double.NaN);
Console.WriteLine("NaN != NaN: {0}", Double.NaN != Double.NaN);
Console.WriteLine("NaN.Equals(NaN): {0}", Double.NaN.Equals(Double.NaN));
Console.WriteLine("! NaN.Equals(NaN): {0}", ! Double.NaN.Equals(Double.NaN));
Console.WriteLine("IsNaN: {0}", Double.IsNaN(Double.NaN));
Console.WriteLine("\nNaN > NaN: {0}", Double.NaN > Double.NaN);
Console.WriteLine("NaN >= NaN: {0}", Double.NaN >= Double.NaN);
Console.WriteLine("NaN < NaN: {0}", Double.NaN < Double.NaN);
Console.WriteLine("NaN < 100.0: {0}", Double.NaN < 100.0);
Console.WriteLine("NaN <= 100.0: {0}", Double.NaN <= 100.0);
Console.WriteLine("NaN >= 100.0: {0}", Double.NaN > 100.0);
Console.WriteLine("NaN.CompareTo(NaN): {0}", Double.NaN.CompareTo(Double.NaN));
Console.WriteLine("NaN.CompareTo(100.0): {0}", Double.NaN.CompareTo(100.0));
Console.WriteLine("(100.0).CompareTo(Double.NaN): {0}", (100.0).CompareTo(Double.NaN));
}
}
// The example displays the following output:
// NaN == NaN: False
// NaN != NaN: True
// NaN.Equals(NaN): True
// ! NaN.Equals(NaN): False
// IsNaN: True
//
// NaN > NaN: False
// NaN >= NaN: False
// NaN < NaN: False
// NaN < 100.0: False
// NaN <= 100.0: False
// NaN >= 100.0: False
// NaN.CompareTo(NaN): 0
// NaN.CompareTo(100.0): -1
// (100.0).CompareTo(Double.NaN): 1
The code is also from MSDN
Upvotes: 3
Reputation: 1852
Using ILSpy I can see that Double.Equals
has some additional logic to check whether either value being compared is NaN.
ILSpy also decompiles the body of ==
to this:
public static bool operator ==(double left, double right)
{
return left == right;
}
The other operators follow the same pattern, which is weird. Perhaps a decompile error?
Upvotes: -1