【问题标题】:Call BeginInvoke on MulticastDelegate?在 MulticastDelegate 上调用 BeginInvoke?
【发布时间】:2011-09-09 16:09:49
【问题描述】:

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

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

注意:为了澄清(因为我犯了这个错误),我说的是代表上的BeginInvoke,而不是控件上的。

【问题讨论】:

  • 如果你同步调用委托,它不知何故知道先运行哪个,为什么异步执行会有什么不同?
  • @svick:我想不会。它按添加顺序调用,对吗?
  • @svick:我从我的问题中排除了我的“猜测”。我真的不知道你为什么不能在MulticastDelegateBeginInvoke

标签: c# .net begininvoke multicastdelegate


【解决方案1】:

我认为 Jon Skeet 在您链接的帖子中做了很好的解释:

您希望线程如何工作?你必须运行每个 同步调用,但异步运行整个事情 关于调用线程,或者你可以运行每个调用 异步?

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

基本上在MulticastDelegate 上调用BeginInvoke 是模棱两可的,您是否希望代表相互等待?虽然理论上它可以为您决定,但已做出选择以强制您通过以不同方式调用委托来显式选择所需的方法。

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

【讨论】:

    【解决方案2】:

    给定任何委托类型,可以很容易地编写一个类,该类将组合属于该类型或派生类型的委托,并生成一个组合委托,该委托几乎可以完成MulticastDelegate 可以做的所有事情,以及一个数字它不能做的事情。组合委托的样式唯一不能做的就是将其子组件由Delegate.Remove 取出(因为该函数只会将组合委托视为一个单元)。与 MulticastDelegate 不同,组合委托将能够包含派生委托类型,并且在只需要一个目标的地方也能正常工作。

    在 vb.net 中,代码类似于:

    类 DoubleAction(Of T) Private _Act1, _Act2 作为动作(T 的) 私有子新(ByVal Act1 作为操作(T),ByVal Act2 作为操作(T)) _Act1 = Act1 _Act2 = Act2 结束子 私有子调用(ByVal Param As T) _Act1(参数) _Act2(参数) 结束子 函数组合(ByVal Act1 作为动作(T),ByVal Act2 作为动作(T))作为动作(T) Dim newAct As New DoubleAction(Of T)(Act1, Act2) 返回地址NewAct.Invoke 结束功能 结束类

    翻译成 C# 应该很简单。

    这种组合委托的方法唯一真正的问题是,要支持的每个泛型委托系列都需要样板代码(因为 .net 不允许将委托用作泛型类型参数)。

    【讨论】:

      【解决方案3】:

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

      根据调用列表从第一个到最后一个依次调用异步方法。

      【讨论】:

        猜你喜欢
        • 2011-06-11
        • 2014-04-18
        • 2015-12-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-04-25
        • 2018-09-11
        • 1970-01-01
        相关资源
        最近更新 更多