2017-01-29 24 views
1

任何人都可以解釋這一點嗎?在通用方法中使用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)); 
} 

(不會讓我發佈無需添加一些文字,所以這裏的一些更多...)

+0

也看看這個:[什麼時候C#中的泛型類型解析?](http://stackoverflow.com/questions/17734247/when-is-the-generic-type-resolved-in-c) – Costas

+0

和這[這是爲什麼通用在編譯時解決?(http://stackoverflow.com/questions/6127855/why-is-this-generic-not-resolved-at-compile-time) – Costas

+0

望着IL,通用方法中的代碼始終是裝箱的,而「main」方法中的代碼不是。 – Costas

回答

3

你的三個調用返回false因爲他們叫Object.Equals(Object)

你在比較盒裝的Int32和盒裝的Int16short),所以它們是兩個不相等的對象,它返回false。 overridesEquals(Object)首先檢查他們收到的盒裝物體是否具有相同的確切類型,其中Int16不是。

a.Equals(b)調用Int32.Equals(Int32),在編譯時將b隱式轉換爲Int32。 因此,該方法會看到兩個具有相同值的Int32,並返回true。

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 

因此,即使在編譯時已知該類型,這些值仍然會被裝箱。