2012-01-20 33 views
10

我想知道爲什麼給定的代碼(在LinqPad執行它)隱式方法團轉化疑難雜症

void Main() { 
    Compare1((Action)Main).Dump(); 
    Compare2(Main).Dump(); 
} 

bool Compare1(Delegate x) { 
    return x == (Action)Main; 
} 

bool Compare2(Action x) { 
    return x == Main; 
} 

的輸出總是:

False 
True 

我已經天真地希望它是True在這兩種情況。

+1

更改'Compare1'以使用'return x ==(Delegate)(Action)Main;'使其返回'true'。不知道爲什麼。 – Joey

+0

僅供參考:我在這裏問了一個相對問題:http://stackoverflow.com/questions/8939350/implicit-method-group-conversion-gotcha-part-2 –

回答

9

這是編譯成IL後的樣子,然後反編譯回C#。請注意,在這兩種情況下都存在new Action(Main)-一個新的參考對象(委託),其中存儲有指向實際方法的指針。

private static void Main() 
{ 
    Program.Compare1(new Action(Program.Main)).Dump(); 
    Program.Compare2(new Action(Program.Main)).Dump(); 
    Console.ReadLine(); 
} 

private static bool Compare1(Delegate x) 
{ 
    return x == new Action(Program.Main); 
} 

private static bool Compare2(Action x) 
{ 
    return x == new Action(Program.Main); 
} 

如果接下來我們就一起來看看到CIL,前者使用ceq(參考比較),而後者使用call bool [mscorlib]System.Delegate::op_Equality(class [mscorlib]System.Delegate, class [mscorlib]System.Delegate)比較代表。

首先返回false,因爲包裝代理的動作是兩個不同的引用對象。

第二個返回true,因爲在Delegate類上實現的相等運算符比較了包裝器(動作)內的實際目標。

7

false結果是關係到使比較1()方法執行在兩個不同的對象引用的比較的事實(compilator示出了相應的警告):

IL_0001: ldarg.0 
IL_0002: ldnull 
IL_0003: ldftn  instance void ConsoleApplication1.Test::Main() 
IL_0009: newobj  instance void [System.Core]System.Action::.ctor(object, 
                    native int) 
IL_000e: ceq <<reference comparison 

可以使用以下代碼避免該問題:

bool Compare1(Delegate x) { 
    return x == (Delegate)((Action)Main); 
}