在通用方法中使用Equals

时间:2017-01-29 17:20:13

标签: .net generics equals

任何人都可以解释这个吗?

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));
}

(我不会在没有添加更多文字的情况下发帖,所以这里还有更多......)

2 个答案:

答案 0 :(得分:3)

您的三个电话会回复false,因为他们会拨打Object.Equals(Object)

您将盒装Int32与装箱Int16short)进行比较,因此他们会选择两个不相等的对象并返回false。 Equals(Object)的{​​{3}}首先检查他们收到的盒装对象是否具有相同的确切类型,Int16不是。

a.Equals(b)调用overrides,在编译时隐式地将b转换为Int32。 因此,该方法看到两个具有相同值的Int32并返回true。

答案 1 :(得分:2)

IL显示:第一个电话被装箱:

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         

第二个不是:

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

为通用方法生成的IL始终是装箱:

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 

并且使用以下方法调用此方法:

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 

所以,即使在编译时已知类型,值仍将被装箱。