在MulticastDelegate上调用BeginInvoke?

10
根据Jon Skeet的说法,“您只能在具有单个目标调用的委托上调用BeginInvoke。”
为什么呢?真正的原因是什么?
注意:为了澄清(并且因为我犯了这个错误),我谈论的是委托上的BeginInvoke,而不是控件上的BeginInvoke。

如果您同步调用委托,它会以某种方式知道先运行哪个,那么为什么异步执行会有所不同呢? - svick
@svick:我猜不是吧。它按添加的顺序调用,对吗? - richard
@svick:我从我的问题中删除了“猜测”。我真的不知道为什么您不能在“MulticastDelegate”上使用“BeginInvoke”。 - richard
3个回答

8
我认为Jon Skeet在您提供的帖子中做了很好的解释:
你希望线程如何工作?您是否必须同步运行每个调用,但整个过程与调用线程异步运行,还是可以异步运行每个调用?
如果是前者,只需运行单个线程池工作项,该工作项同步调用委托。如果是后者,请使用Delegate.GetInvocationList获取调用列表,并依次调用列表中的元素。
基本上,在MulticastDelegate上调用BeginInvoke是有歧义的,您想让委托互相等待还是不等待?虽然理论上它可以为您决定,但选择是强制您通过以不同的方式调用委托来明确选择您想要的方法。
换句话说,这是一种避免混淆的设计选择。此外,需要注意的是,BeginInvoke已经不再流行,现在有更多新的异步编程方法可用,因此更新这个旧标准的可能性很小,即使他们现在想要更改,也没有理由去更改。

0

给定任何委托类型,我们可以相当容易地编写一个类,该类将组合那种类型或派生类型的委托,并产生一个组合委托,该委托几乎可以做到 MulticastDelegate 可以做的一切事情,以及一些它不能做的事情。这种组合委托风格唯一无法做到的是通过 Delegate.Remove 将其子组件取出(因为该函数将把组合委托视为一个单元)。与 MulticastDelegate 不同,组合委托将能够包括派生委托类型,并且在只想要一个目标的地方也能正常工作。

在 vb.net 中,代码可能如下:

双动作类(DoubleAction) 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

还有一种解决方法是在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();
   }

}

异步方法根据调用列表从第一个到最后一个被顺序调用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接