Reputation: 181
Anyone can explain this?
void Main()
{
int a = 1;
short b = 1;
Console.WriteLine(b.Equals(a)); // false
Console.WriteLine(a.Equals(b)); // true
Test<int, short>(a, b); // prints: false, false
Test(a, b); // prints: false, false
}
void Test<T1, T2>(T1 x, T2 y)
{
Console.WriteLine(y.Equals(x));
Console.WriteLine(x.Equals(y));
}
(Wouldn't let me post without adding some more text, so here's some more...)
Upvotes: 1
Views: 57
Reputation: 181
The IL shows this: The first call is boxed:
IL_0000: nop
IL_0001: ldc.i4.1
IL_0002: stloc.0 // a
IL_0003: ldc.i4.1
IL_0004: stloc.1 // b
IL_0005: ldloca.s 01 // b
IL_0007: ldloc.0 // a
IL_0008: box System.Int32
IL_000D: call System.Int16.Equals
IL_0012: call System.Console.WriteLine
IL_0017: nop
IL_0018: ret
The second is not:
IL_0000: nop
IL_0001: ldc.i4.1
IL_0002: stloc.0 // a
IL_0003: ldc.i4.1
IL_0004: stloc.1 // b
IL_0005: ldloca.s 00 // a
IL_0007: ldloc.1 // b
IL_0008: call System.Int32.Equals
IL_000D: call System.Console.WriteLine
IL_0012: nop
IL_0013: ret
The IL generated for the generic method is always boxing:
Test<T1,T2>:
IL_0000: nop
IL_0001: ldarga.s 02
IL_0003: ldarg.1
IL_0004: box T1
IL_0009: constrained. T2
IL_000F: callvirt System.Object.Equals
IL_0014: call System.Console.WriteLine
IL_0019: nop
IL_001A: ldarga.s 01
IL_001C: ldarg.2
IL_001D: box T2
IL_0022: constrained. T1
IL_0028: callvirt System.Object.Equals
IL_002D: call System.Console.WriteLine
IL_0032: nop
IL_0033: ret
and a call to this method is done with:
IL_0000: nop
IL_0001: ldc.i4.1
IL_0002: stloc.0 // a
IL_0003: ldc.i4.1
IL_0004: stloc.1 // b
IL_0005: ldarg.0
IL_0006: ldloc.0 // a
IL_0007: ldloc.1 // b
IL_0008: call Test<Int32,Int16>
IL_000D: nop
IL_000E: ret
so, even when the type is known at compile time, the values will still be boxed.
Upvotes: 2
Reputation: 887305
Your three calls return false
because they call Object.Equals(Object)
.
You're comparing a boxed Int32
with a boxed Int16
(short
), so they're two unequal objects and it returns false.
The overrides of Equals(Object)
first check that the boxed object they receive is of the same exact type, which Int16
isn't.
a.Equals(b)
calls Int32.Equals(Int32)
, implicitly converting b
to Int32
at compile time.
Therefore, that method sees two Int32
s with the same value and returns true.
Upvotes: 3