私は通常、非同期に表示されるアラートウィンドウ(Telerik WPF)で作業しています(開いている間はコードが実行され続けます)。async/ awaitを使用して同期させたいです。
私はこれをTaskCompletionSource
で動作させていますが、そのクラスは汎用であり、戻り値のない単純なTask
だけが必要なときにTask<bool>
のようなオブジェクトを返します。
public Task<bool> ShowAlert(object message, string windowTitle)
{
var dialogParameters = new DialogParameters { Content = message };
var tcs = new TaskCompletionSource<bool>();
dialogParameters.Closed += (s, e) => tcs.TrySetResult(true);
RadWindow.Alert(dialogParameters);
return tcs.Task;
}
そのメソッドを呼び出すコードは
await MessageBoxService.ShowAlert("The alert text.")
dialogParameters.Closed
イベントが発生するまで待機できる、同様に機能する非汎用タスクを返すにはどうすればよいですか?このコードで返されるbool
を無視できることを理解しています。私はそれとは異なる解決策を探しています。
メソッドは次のように変更できます。
public Task ShowAlert(object message, string windowTitle)
Task<bool>
はTask
を継承するため、Task<bool>
Task
のみを呼び出し元に公開します
編集:
Stephen Toubによる「The-based-based Asynchronous pattern」というタイトルのMicrosoftドキュメント http://www.Microsoft.com/en-us/download/details.aspx?id=19957 を見つけました。この同じパターンを推奨する次の抜粋があります。
TaskCompletionSource <TResult>に対応する非ジェネリック版はありません。ただし、Task <TResult>はTaskから派生しているため、一般的なTaskCompletionSource <TResult>は、ダミーのTResultを持つソースを利用して単純にTaskを返すI/Oにバインドされたメソッドに使用できます(ブールは適切なデフォルトの選択であり、開発者がTask <TResult>にダウンキャストするTaskのコンシューマーを心配している場合、プライベートTResultタイプを使用できます)
情報を漏らしたくない場合、一般的なアプローチはTaskCompletionSource<object>
およびnull
の結果で完了します。次に、それをTask
として返します。
Nito.AsyncEx は、上記の@StephenCleary氏の功績により、非ジェネリックTaskCompletionSource
クラスを実装します。
@Kevin Kalitowskiから
スティーブントーブによる「The Task-based Asynchronous pattern」というタイトルのMicrosoftドキュメント http://www.Microsoft.com/en-us/download/details.aspx?id=19957 を見つけました。
このドキュメントには、Kevinが指摘しているように、この問題を扱う例があります。これは例です:
public static Task Delay(int millisecondsTimeout)
{
var tcs = new TaskCompletionSource<bool>();
new Timer(self =>
{
((IDisposable)self).Dispose();
tcs.TrySetResult(true);
}).Change(millisecondsTimeout, -1);
return tcs.Task;
}
最初は、コンパイルメッセージなしではメソッドに「async」修飾子を直接追加できないため、良くないと思いました。ただし、メソッドを少し変更すると、メソッドはasync/awaitでコンパイルされます。
public async static Task Delay(int millisecondsTimeout)
{
var tcs = new TaskCompletionSource<bool>();
new Timer(self =>
{
((IDisposable)self).Dispose();
tcs.TrySetResult(true);
}).Change(millisecondsTimeout, -1);
await tcs.Task;
}
編集:最初はこぶを乗り越えたと思った。しかし、アプリで同等のコードを実行すると、このコードはtcs.Task;を待機するときにアプリをハングさせるだけです。ですから、これはasync/await c#構文の重大な設計上の欠陥だとまだ信じています。