2013-05-02 74 views
11

我發現了兩種不同的方式來初始化一個代表與行動:行動委託:新的行動或鑄造行動?

創建一個新的行動或轉換爲行動。

Delegate foo = new Action(() => DoNothing(param)); 
Delegate bar = (Action)(() => DoNothing(param)); 

這2個語法有區別嗎?

哪一個更好?爲什麼?

編輯:
代表在本例中使用,因爲語法是調用像BeginInvoke的方法或lambda表達式調用有用的,投lambda表達式爲行動

static main 
{ 
    Invoke((Action)(() => DoNothing())); // OK 
    Invoke(new Action(() => DoNothing())); // OK 
    Invoke(() => DoNothing()); // Doesn't compil 
} 

private static void Invoke(Delegate del) { } 
很重要

但有趣的是,編譯器授權此:

Action action =() => DoNothing(); 
Invoke(action); 
+0

您的編輯:什麼有意義內容會在你的靜態'Invoke'方法中出現嗎? – 2013-05-03 08:47:36

+0

沒有什麼有趣的。問題的目的只是爲了理解2種語法之間的區別。我真正的實現是在WPF應用程序中,當我調用Dispatcher.Invoke()(http://msdn.microsoft.com/en-us/library/cc647509(v=vs.100).aspx) – Hyralex 2013-05-03 08:59:35

+1

我明白了。你應該還記得'Action' ___是'Delegate',因爲'Action'來自'Delegate'。所以即使你使用了一個接受'Delegate'的重載,你也可以給它一個'Action'。例如:'Action bar =()=> DoNothing(param); someDispatcher.BeginInvoke(bar);'(參見[Dispatcher.BeginInvoke]](http://msdn.microsoft.com/zh-cn/library/cc190824.aspx))。補充:在.NET 4.5的新版本中,有''Dispatcher.Invoke'重載'Action',但這只是爲了方便起見,請參閱http://msdn.microsoft.com/en-us/library /hh199416.aspx。 – 2013-05-03 09:15:54

回答

10

這兩條指令沒有區別。在這兩條指令中,都會創建一個Action的新實例。

下面的IL代碼似乎證實了這一點。

控制檯程序:

class Program 
{ 
    static void Main(string[] args) 
    { 
     Delegate barInit = (Action)(() => DoNothing()); 
     Delegate fooInit = new Action(() => DoNothing()); 
    } 

    private static void DoNothing() { } 
} 

IL代碼:

// First instruction 
IL_0000: ldsfld class [mscorlib]System.Action CodeMachineTest.Program::'CS$<>9__CachedAnonymousMethodDelegate2' 
IL_0005: brtrue.s IL_0018 

IL_0007: ldnull 
IL_0008: ldftn void CodeMachineTest.Program::'<Main>b__0'() 

// Create a new Action instance for the instruction (Action)(() => DoNothing()) 
IL_000e: newobj instance void [mscorlib]System.Action::.ctor(object, native int) 

IL_0013: stsfld class [mscorlib]System.Action CodeMachineTest.Program::'CS$<>9__CachedAnonymousMethodDelegate2' 

IL_0018: ldsfld class [mscorlib]System.Action CodeMachineTest.Program::'CS$<>9__CachedAnonymousMethodDelegate2' 
IL_001d: pop 

// Second instruction 
IL_001e: ldsfld class [mscorlib]System.Action CodeMachineTest.Program::'CS$<>9__CachedAnonymousMethodDelegate3' 
IL_0023: brtrue.s IL_0036 

IL_0025: ldnull 
IL_0026: ldftn void CodeMachineTest.Program::'<Main>b__1'() 
IL_002c: newobj instance void [mscorlib]System.Action::.ctor(object, native int) 
IL_0031: stsfld class [mscorlib]System.Action CodeMachineTest.Program::'CS$<>9__CachedAnonymousMethodDelegate3' 

IL_0036: ldsfld class [mscorlib]System.Action CodeMachineTest.Program::'CS$<>9__CachedAnonymousMethodDelegate3' 
IL_003b: pop 
IL_003c: ret 
2

在我看來,沒有區別。

new Action(() => DoNothing(param)); 

這只是創建一個新的動作,並沿Lambda表達式,該編譯器會處理,並看到它,一切都連接好就好了通行證。

(Action)(() => DoNothing(param)); 

這工作,因爲一個lambda方法,像這樣沒有返回值和不帶任何參數,這樣編譯器可以驗證它是「可映射」,理由的行動,它去通過委託系統。

它們或多或少都是相同的,這取決於任何類型的編譯器優化,很難說哪個更高性能,或許您應該測試性能並親自看看?

這是一個有趣的問題,並探索到委託系統和LINQ和表達式如何適應

new Func<string>(() => "Boo!"); 

是更多或更少等效於:

(Func<String>)() => "Boo!"; 

至於我我們知道他們最終都會通過代表系統認爲Invoke()等,如果您測試了性能並分享了您的結果,那將會很有趣。

+1

我做了一些測試,沒有區別。拆卸後,IL和機器代碼是相同的。 – Hyralex 2013-05-02 01:46:29

+1

這並不特別有趣,它們只是導致相同IL的兩種語法。所以這和表演沒有關係,所以你想讓他分享什麼?如果您需要詳細信息,請閱讀C#語言規範。第一個表達式位於_7.6.10.5委託創建表達式_中,第二個表達式位於_6.5匿名函數轉換_中。章節編號來自文檔的5.0版本。請注意,7.6.10.5清楚地表明它的處理方式與6.5中的相同。 – 2013-05-03 08:41:27

0

有沒有區別,他們對同一只兩種語法。就我個人而言,我使用最後一個,因爲它更短。

但是,爲什麼你需要一個Delegate類型的變量?在大多數情況下,你希望變量具有相同類型的實例,然後你可以使用

var bar = (Action)(() => DoNothing(param)); 

Action bar =() => DoNothing(param); 

,而不是

Delegate bar = (Action)(() => DoNothing(param)); // (from your question) 
+0

一些像Invoke或BeginInvoke這樣的方法需要一個Delegate,並且需要強制轉換或創建一個Action來使用lambda表達式。 – Hyralex 2013-05-02 22:54:48

+0

@Hyralex但是所有具體的委託類型,包括'System.Action',都從System.Delegate派生(通過'System.MulticastDelegate')。因此方法'Invoke'和'BeginInvoke'和其他成員被繼承。所以你可以說'Action bar =()=> DoNothing(param); bar.BeginInvoke(...);'。所以我不明白。 – 2013-05-03 08:20:08

+0

我正在談論像分派器這樣的現有對象的BeginInvoke和Invoke。我編輯了我的問題,以提供更多示例。 – Hyralex 2013-05-03 08:25:55