在MulticastDelegate上调用BeginInvoke?

时间:2011-06-06 22:43:55

标签: c# .net begininvoke multicastdelegate

根据Jon Skeet,“您只能在具有单个目标调用的委托上调用BeginInvoke。”

为什么?真正的原因是什么?

注意:为了澄清(因为我犯了这个错误),我说的是关于委托的BeginInvoke,而不是关于控件。

3 个答案:

答案 0 :(得分:7)

我认为Jon Skeet在您关联的帖子中做得很好:

  

您希望线程如何工作?你必须运行每一个   同步调用,但与异步运行整个事物   尊重调用线程,或者你可以运行每个调用   异步?

     

如果是前者,只需运行一个调用的线程池工作项   代表同步。如果是后者,请获取调用列表   使用Delegate.GetInvocationList并在元素上调用BeginInvoke   依次列出。

基本上在BeginInvoke上调用MulticastDelegate是不明确的,您是否希望代表彼此等待?虽然从理论上讲它可以为你决定,但是已经做出选择,迫使你通过以不同的方式调用代表来明确选择你想要的方法。

换句话说,它是避免混淆的设计选择。另外值得注意的是BeginInvoke已经不再受欢迎,并且可以使用更新的异步编程方法,因此不太可能更新这个旧标准,所以即使他们现在想要改变,也没有理由。

答案 1 :(得分:0)

给定任何委托类型,可以相当容易地编写一个类,该类将组合该类型或派生类型的委托,并产生一个组合委托,它将完成MulticastDelegate可以做的所有事情,以及它不能做的一些事情。组合委托的风格唯一不能做的就是让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不允许将委托用作泛型类型参数)。

答案 2 :(得分:0)

还有一种解决方法可以在System.MulticastDelegate对象上调用BeginInvoke方法:

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

}

因此,从第一个到最后一个调用异步方法,具体取决于调用列表。