このコードは Task または Task<object> を返す必要がありますか?
-
21-12-2019 - |
質問
読んでいた TaskCompletionSource の性質, 、Stephen Toub による投稿。
public static Task RunAsync(Action action)
{
var tcs = new TaskCompletionSource<Object>();
ThreadPool.QueueUserWorkItem(_ =>
{
try
{
action();
tcs.SetResult(null);
}
catch(Exception exc) { tcs.SetException(exc); }
});
return tcs.Task;
}
もう種類は気にしないので、
T
つまり、私はデフォルトで使用していますObject
. 。そして、Action
正常に実行され、SetResult
を移行するために今でも使用されていますTask
にRanToCompletion
最終状態。ただし、実際の結果の値は無関係であるため、null
使用されている。 ついに、RunAsync
戻り値Task
それよりもTask<Object>
. 。もちろん、インスタンス化されたtask
のタイプはまだですTask<Object>
, しかし、それ自体を参照する必要はなく、このメソッドの利用者はそれらの実装の詳細を気にする必要はありません。
なぜメソッドが返されるのか特にわかりません Task
それよりも Task<object>
(太字の文を強調したのはそのためです)。メソッドが return に設定されていることは知っています Task
しかし tcs
です TaskCompletionSource<Object>
, 、 ない TaskCompletionSource
(それは間違っていると思います)。
解決
一般的なTaskCompletionSource
は存在しないため、必要なすべてのタスクはその結果、結果は問題ではありません。
呼び出し側は、タスクが実際にはTask<object>
であることを知らせていません。発信者は実際の結果に気付いていません。
もちろん、await
がTask<T>
Falseを返すTask
を見つけるのも一般的です。
他のヒント
TaskCompletionSource
のインスタンスではないTask
のインスタンスを作成するための非一般的なTask<T>
クラスはありません。これにより、戻り値を気にしない(または提供されていない)ときに、TaskCompletionSource<T>
のGeneric Typeパラメータに2つのオプションが残っています。
- Return型として、
object
などの任意の既存のタイプを使用します。タスクの完了を示すには、値をnull
に設定します。 - 特定の非公開タイプを使用し、タスクの完了を示すために値を
null
に設定します。
戻り値がないTaskCompletionSource<T>
を提供する目的でTask
インスタンスを作成するときは、専用の非公開タイプを使用して、その結果、結果が発生したTask
のインスタンスとして返されたTask<T>
を間違えないようにします。意味。
まず、次のクラスを定義します(別の型の内側にネストされている場合はprivate sealed class
にすることができます):
internal sealed class VoidResult
{
}
.
その後、完了元のTaskCompletionSource<object>
を使用する代わりに、TaskCompletionSource<VoidResult>
を使用します。 VoidResult
タイプはコードを呼び出してアクセスできないため、ユーザーはTask
オブジェクトをTask<VoidResult>
のインスタンスにキャストできません。
なぜメソッドが返されるのか特にわかりません
Task
それよりもTask<object>
だって帰ってきたら Task<Object>
これは、このメソッドが完了すると、次の型の有用な値が生成されることを意味します。 Object
. 。この場合、結果は何も生成されません。だからこそ、スティーブンは戻ることを選択します。 Task
.
私たちが扱っているのであれば Func<Object>
それから戻る Task<Object>
として適切でしょう Func
何らかの結果が生成される場合は、それを返すことを選択する場合があります。
なぜ
TaskCompletionSource<Object>
, 、 ないTaskCompletionSource
?
そんなことないから。非ジェネリックはありません TaskCompletionSource
.
Task<object>
を返した場合、var result = await RunAsync(...)
は常に結果を設定しているものです。
クライアントはこれを気にしませんので、null
を返します。
理想的には、Task
の代わりにTaskCompletionSource
を内部的に使用し、TaskCompletionSource<object>
の代わりにSetCompleted()
のようなものと呼びます。しかし、そのような種類は存在しません。