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?
For a value type, you should always override Equals, because tests for equality that rely on reflection offer poor performance. You can also override the default implementation of Equals for reference types to test for value equality instead of reference equality and to define the precise meaning of value equality.
Because Complex is a value type, it cannot be derived from. Therefore, the override to Equals(Object) method need not call GetType to determine the precise run-time type of each object, but can instead use the is operator in C# or the TypeOf operator in Visual Basic to check the type of the obj parameter.
With value types, you should always override the == operator. Like the Equals method, the default implementation of the == operator uses reflection and is slow. Use the same logic as the Equals method, and you'll get much better performance when you're doing equality comparisons on value types.
Equals(Int32) This method is used to return a value indicating whether the current instance is equal to a specified Int32 value or not. Syntax: public bool Equals (int obj);
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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With