根据Jon Skeet的说法,“您只能在具有单个目标调用的委托上调用 BeginInvoke。”
这是为什么?真正的原因是什么?
注意:为了澄清(并且因为我犯了这个错误),我说的BeginInvoke
是代表,而不是控制。
根据Jon Skeet的说法,“您只能在具有单个目标调用的委托上调用 BeginInvoke。”
这是为什么?真正的原因是什么?
注意:为了澄清(并且因为我犯了这个错误),我说的BeginInvoke
是代表,而不是控制。
我认为 Jon Skeet 在您链接的帖子中做了很好的解释:
你希望线程如何工作?您是否必须同步运行每个调用,但相对于调用线程异步运行整个事情,或者您可以异步运行每个调用?
如果是前者,只需运行一个同步调用委托的线程池工作项。如果是后者,则通过Delegate.GetInvocationList 获取调用列表,并在列表元素上依次调用BeginInvoke。
基本上调用BeginInvoke
aMulticastDelegate
是模棱两可的,您是否希望代表互相等待?虽然理论上它可以为您决定,但已做出选择以强制您通过以不同方式调用委托来显式选择所需的方法。
换句话说,这是一种避免混淆的设计选择。同样重要的是要注意,它BeginInvoke
已经失宠,并且有更新的异步编程方法可用,因此不太可能更新这个旧标准,所以即使他们现在想改变,也没有理由这样做。
给定任何委托类型,一个人可以很容易地编写一个类,它将组合属于该类型或派生类型的委托并产生一个组合委托,该委托将完成几乎所有MulticastDelegate
可以做的事情,以及一些它不能做的事情. 组合委托的样式唯一不能做的就是将其子组件取出Delegate.Remove
(因为该函数只会将组合委托视为一个单元)。与 MulticastDelegate 不同,组合委托将能够包含派生委托类型,并且在只需要一个目标的地方也能正常工作。
在 vb.net 中,代码类似于:
类 DoubleAction(Of T) Private _Act1, _Act2 作为 Action(Of 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 不允许将委托用作泛型类型参数)。
还有一种解决方法可以在 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();
}
}
因此,根据调用列表从第一个到最后一个调用异步方法。