简体   繁体   中英

Use of Equals in generic method

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

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM