web-dev-qa-db-ja.com

WPF DispatcherのInvokeAsyncとBeginInvokeの違いは何ですか

.NET 4.5では、 WPF DispatcherInvokeAsync と呼ばれるDispatcherのスレッドで処理を実行する新しいメソッドセットを取得したことに気付きました。以前、.NET 4.5には InvokeBeginInvoke があり、それぞれこれを同期的および非同期的に処理していました。

命名と利用可能なわずかに異なるオーバーロードに加えて、BeginInvokeメソッドとInvokeAsyncメソッドの間に大きな違いはありますか?

ああ、私はすでにチェックしました、両方ともawaitedにすることができます:

private async Task RunStuffOnUiThread(Action action)
{
    // both of these works fine
    await dispatcher.BeginInvoke(action);
    await dispatcher.InvokeAsync(action);
}
60
Isak Savo

BeginInvokeメソッドはprivate LegacyBeginInvokeImplメソッドを呼び出しますが、このメソッドはprivateメソッドInvokeAsyncImplInvokeAsyncで使用されるメソッド)を呼び出します。基本的に同じことです。単純なリファクタリングのように見えますが、BeginInvokeメソッドが古いものとしてフラグ付けされていなかったのは奇妙です。

BeginInvoke:

public DispatcherOperation BeginInvoke(DispatcherPriority priority, Delegate method)
{
    return this.LegacyBeginInvokeImpl(priority, method, null, 0);
}

private DispatcherOperation LegacyBeginInvokeImpl(DispatcherPriority priority, Delegate method, object args, int numArgs)
{
    Dispatcher.ValidatePriority(priority, "priority");
    if (method == null)
    {
        throw new ArgumentNullException("method");
    }
    DispatcherOperation dispatcherOperation = new DispatcherOperation(this, method, priority, args, numArgs);
    this.InvokeAsyncImpl(dispatcherOperation, CancellationToken.None);
    return dispatcherOperation;
}

InvokeAsync:

public DispatcherOperation InvokeAsync(Action callback, DispatcherPriority priority)
{
    return this.InvokeAsync(callback, priority, CancellationToken.None);
}

public DispatcherOperation InvokeAsync(Action callback, DispatcherPriority priority, CancellationToken cancellationToken)
{
    if (callback == null)
    {
        throw new ArgumentNullException("callback");
    }
    Dispatcher.ValidatePriority(priority, "priority");
    DispatcherOperation dispatcherOperation = new DispatcherOperation(this, priority, callback);
    this.InvokeAsyncImpl(dispatcherOperation, cancellationToken);
    return dispatcherOperation;
}
44
Sisyphe

例外処理は異なります。

以下を確認することをお勧めします。

private async void OnClick(object sender, RoutedEventArgs e)
{
    Dispatcher.UnhandledException += OnUnhandledException;
    try
    {
        await Dispatcher.BeginInvoke((Action)(Throw));
    }
    catch
    {
        // The exception is not handled here but in the unhandled exception handler.
        MessageBox.Show("Catched BeginInvoke.");
    }

    try
    {
       await Dispatcher.InvokeAsync((Action)Throw);
    }
    catch
    {
        MessageBox.Show("Catched InvokeAsync.");
    }
}

private void OnUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
    MessageBox.Show("Catched UnhandledException");
}

private void Throw()
{
    throw new Exception();
}
21
Wouter

メソッドのシグネチャには違いがあります。

_BeginInvoke(Delegate, Object[])
InvokeAsync(Action)
_

BeginInvoke()の場合、コンパイラは暗黙的に配列_Object[]_を作成しますが、InvokeAsync()の場合、このような配列は必要ありません。

_IL_0001:  ldarg.0
IL_0002:  call       instance class [WindowsBase]System.Windows.Threading.Dispatcher [WindowsBase]System.Windows.Threading.DispatcherObject::get_Dispatcher()
IL_0007:  ldarg.1
IL_0008:  ldc.i4.0
IL_0009:  newarr     [mscorlib]System.Object
IL_000e:  callvirt   instance class [WindowsBase]System.Windows.Threading.DispatcherOperation [WindowsBase]System.Windows.Threading.Dispatcher::BeginInvoke(class [mscorlib]System.Delegate, object[])


IL_0014:  ldarg.0
IL_0015:  call       instance class [WindowsBase]System.Windows.Threading.Dispatcher [WindowsBase]System.Windows.Threading.DispatcherObject::get_Dispatcher()
IL_001a:  ldarg.1
IL_001b:  callvirt   instance class [WindowsBase]System.Windows.Threading.DispatcherOperation [WindowsBase]System.Windows.Threading.Dispatcher::InvokeAsync(class [mscorlib]System.Action)
_
13
user2341923

さて、私が気づいた違いの1つは、InvokeAsyncには、戻り値としてDispatcherOperationを返し、デリゲート入力パラメーターとしてFuncを受け入れる汎用オーバーロードがあることです。したがって、タスクの結果を待つ方法に似たタイプセーフな方法で、InvokeAsyncを介して操作の結果を取得できます。

2
Chris S.