2011-06-06 47 views
9

根據Jon Skeet,「只能對具有單個目標調用的委託調用BeginInvoke」。在MulticastDelegate上調用BeginInvoke?

這是爲什麼?真正的原因是什麼?

注:爲了清楚(因爲我犯了這個錯誤),我就代表談論BeginInvoke,而不是控制。

+0

如果您同步調用委託,它會以某種方式知道首先運行哪個委託,爲什麼異步執行應該有任何不同? – svick 2011-06-06 23:33:40

+0

@svick:我想這不會。它按照它們添加的順序調用,是正確的? – richard 2011-06-06 23:34:34

+0

@svick:我把我的「猜測」帶出了我的問題。我真的不知道爲什麼你不能在'MulticastDelegate'上'BeginInvoke'。 – richard 2011-06-06 23:36:53

回答

7

我覺得喬恩斯基特做得很好的文章,解釋你鏈接:

你怎麼想的線程工作?您是否必須同步運行每個 調用,但是請以關於調用線程的 異步運行整個事件,還是可以異步運行每個調用 ?

如果是前者,只需運行一個單線程池工作項,即同步調用 委託。如果是後者,請使用Delegate.GetInvocationList獲取調用列表 ,並依次在 列表的元素上調用BeginInvoke。

MulticastDelegate基本上調用BeginInvoke是模糊的,你要代表等待對方或不?雖然理論上它可以爲你做出決定,但是你已經做出選擇,迫使你通過以不同的方式調用委託來顯式選擇你想要的方法。

換句話說,這是避免混淆的設計選擇。另外值得注意的是,BeginInvoke已經不受歡迎,並且新的異步編程方法可用,使得不太可能更新這個舊標準,所以即使他們現在想改變,也沒有理由。

0

鑑於任何委託類型,人們可以很容易地編寫一個類,該類將組合委託類型或派生類型,並生成一個組合委託,該組合委託幾乎可以做任何事情,以及一些事情不能。組合代表風格無法做到的唯一情況是其子組件由Delegate.Remove取出(因爲該函數僅將組合代表作爲一個單元)。與MulticastDelegate不同,合併的委託可以包含派生的委託類型,並且在只需要一個目標的地方工作得很好。

在vb.net,代碼將是這樣的:

 
Class DoubleAction(Of T) 
    Private _Act1, _Act2 As Action(Of T) 
    Private Sub New(ByVal Act1 As Action(Of T), ByVal Act2 As Action(Of T)) 
     _Act1 = Act1 
     _Act2 = Act2 
    End Sub 
    Private Sub Invoke(ByVal Param As T) 
     _Act1(Param) 
     _Act2(Param) 
    End Sub 
    Function Combine(ByVal Act1 As Action(Of T), ByVal Act2 As Action(Of T)) As Action(Of T) 
     Dim newAct As New DoubleAction(Of T)(Act1, Act2) 
     Return AddressOf newAct.Invoke 
    End Function 
End Class 

翻譯到C#應該是簡單的。

這種組合代表的方法唯一的問題是每個通用的代理類需要支持樣板代碼(因爲.net不允許將代表用作泛型類型參數)。

0

還有一種解決方法,以調用BeginInvoke方法的System.MulticastDelegate對象上:

public class Program{ 

    public delegate void SayHello(); 

    public void SayHelloAndWait(){ 
     Console.WriteLine("HELLO.."); 
     System.Threading.Thread.Sleep(5000); 
     Console.WriteLine("..WORLD!"); 
    } 

    public void SayHi(){ 
     Console.WriteLine("Hi world!"); 
    } 

    public void Run(){ 
     SayHello helloMethods; 
     helloMethods = SayHelloAndWait; 
     helloMethods += SayHi; 
     foreach(SayHello hello in helloMethods.GetInvocationList()) 
     hello.BeginInvoke(null,null); 
    } 

    public static void Main(String[] args){ 
     new Program().Run(); 
     Console.Read(); 
    } 

} 

異步方法是從第一個到最後取決於調用列表上從而調用。

相關問題