web-dev-qa-db-ja.com

Dispatcher.BeginInvoke()でasync / awaitを使用する

await操作を実行するコードを含むメソッドがあります。

_public async Task DoSomething()
{
    var x = await ...;
}
_

Dispatcherスレッドで実行するコードが必要です。現在、Dispatcher.BeginInvoke()は待機可能ですが、その中からasyncを実行するために、ラムダをawaitとしてマークすることはできません。

_public async Task DoSomething()
{
    App.Current.Dispatcher.BeginInvoke(async () =>
        {
            var x = await ...;
        }
    );
}
_

内部asyncで、次のエラーが表示されます。

ラムダ式はデリゲート型ではないため、「System.Delegate」型に変換できません。

Dispatcher.BeginInvoke()内からasyncを操作するにはどうすればよいですか?

25
Gigi

その他の回答 は、あいまいなバグを導入した可能性があります。このコード:

_public async Task DoSomething()
{
    App.Current.Dispatcher.Invoke(async () =>
    {
        var x = await ...;
    });
}
_

Dispatcher.Invoke(Action callback) _Dispatcher.Invoke_のオーバーライド形式を使用します。これは、この特定の場合に_async void_ラムダを受け入れます。通常、 _async void_メソッド で発生するため、これは非常に予期しない動作につながる可能性があります。

おそらく次のようなものを探しています:

_public async Task<int> DoSomethingWithUIAsync()
{
    await Task.Delay(100);
    this.Title = "Hello!";
    return 42;
}

public async Task DoSomething()
{
    var x = await Application.Current.Dispatcher.Invoke<Task<int>>(
        DoSomethingWithUIAsync);
    Debug.Print(x.ToString()); // prints 42
}
_

この場合、 _Dispatch.Invoke<Task<int>>_ は_Func<Task<int>>_引数を受け入れ、対応する_Task<int>_を返します。これは待機可能です。 DoSomethingWithUIAsyncから何も返す必要がない場合は、_Task<int>_の代わりにTaskを使用します。

または、 _Dispatcher.InvokeAsync_ メソッドのいずれかを使用します。

48
noseratio