Jon Skeetによると、「BeginInvokeを呼び出すことができるのは、単一のターゲット呼び出しを持つデリゲートでのみです。」
何故ですか?本当の理由は何ですか?
注:明確にするために(そして私がこの間違いを犯したため)、私はBeginInvoke
コントロールではなく、デリゲートについて話している。
Jon Skeetによると、「BeginInvokeを呼び出すことができるのは、単一のターゲット呼び出しを持つデリゲートでのみです。」
何故ですか?本当の理由は何ですか?
注:明確にするために(そして私がこの間違いを犯したため)、私はBeginInvoke
コントロールではなく、デリゲートについて話している。
Jon Skeetは、あなたがリンクした投稿で説明するのに良い仕事をしていると思います。
スレッドをどのように機能させますか?各呼び出しを同期的に実行する必要がありますが、呼び出し元のスレッドに関してすべてを非同期的に実行する必要がありますか、それとも各呼び出しを非同期的に実行できますか?
前者の場合は、デリゲートを同期的に呼び出す単一のスレッドプール作業項目を実行するだけです。後者の場合は、Delegate.GetInvocationListを使用して呼び出しリストを取得し、リストの要素に対して順番にBeginInvokeを呼び出します。
BeginInvoke
基本的に、aの呼び出しMulticastDelegate
はあいまいですが、代理人がお互いを待つようにしますか?理論的にはそれがあなたのために決めることができますが、別の方法でデリゲートを呼び出すことによって、あなたが望むメソッドを明示的に選択することを強制するという選択がなされました。
言い換えれば、混乱を避けるための設計上の選択です。BeginInvoke
また、人気がなくなり、非同期プログラミングの新しい方法が利用可能になり、この古い標準を更新する可能性が低くなっていることに注意することが重要です。したがって、今変更したい場合でも、変更する理由はありません。
任意のデリゲート型が与えられると、その型または派生型のいずれかのデリゲートを組み合わせて、できることのほぼすべてMulticastDelegate
を実行し、実行できない多くのことを実行する結合されたデリゲートを生成するクラスをかなり簡単に作成できます。 。結合されたデリゲートのスタイルで実行できない唯一のことは、そのサブコンポーネントがによって取り出されることですDelegate.Remove
(その関数は結合されたデリゲートを1つのユニットと見なすだけなので)。MulticastDelegateとは異なり、結合されたデリゲートは派生デリゲートタイプを含めることができ、1つのターゲットのみが必要な場所で問題なく機能します。
vb.netでは、コードは次のようになります。
クラスDoubleAction(Of T) プライベート_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 サブ終了 プライベートサブ呼び出し(ByVal Param As T) _Act1(Param) _Act2(Param) サブ終了 関数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) 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();
}
}
その結果、非同期メソッドは、呼び出しリストに応じて最初から最後まで呼び出されます。