私はソケットの読み取りをループしているタスクがあります。
private async void readLoop() {
while (!cts.IsCancelRequested()) {
await socket.ReceiveAsync(data, ...);
doWork(data);
}
}
そして、タスクが作成されたらすぐに実行する必要はないので、私はTask
ではなく、コンストラクターTask.Run
。
private Task readTask = new Task(readLoop, cts, LongRunning);
// when the task need to run:
readTask.Start()
この時点では、タスクを終了する必要があるときは、私が呼び出すときを除いて、それはうまく動作します。readTask.Wait()
またはawait readTask
で例外が発生しましたReceiveAsync
またはdoWork
に添付されていませんreadTask
。例外があったとしても、readTask.Status
ですRunToComplete
そしてreadTask.Exception
ですnull
。アコード。ドキュメントによると、これはasyncメソッドがvoidを返すためですが、私がこれを試したとき:
private async Task readLoop() {...}
コンパイルされません:
error CS0407: 'Task WebSocketInitiator.readLoop()' has the wrong return type
タスクを後で開始し、同時にタスクで発生した例外を追跡し続けるようにする方法はありますか。
問題を示すための最小限のテストケースhttps://dotnetfiddle.net/JIfDIn
私があなたが正しく理解しているならば、あなたはそれが必要とされるまでタスクを実行することを延期したいです、しかし、あなたはコンストラクタで創造を続けたいです。それは結構です、そしてこのような状況のために使われるパターンがあります。それは呼ばれていますLazy
。
しかし、Lazyは非同期ではありません。Stephen TaubはAsyncLazyという非同期の実装を作成しました。
表示されたエラーメッセージが表示されたのは、作成した外側のTaskの戻り値を指定しなかったためです。また戻る必要がありますfoo
の値内側のTaskを返すラムダで呼び出しをラップすると、それを取得することができます。
var task1 = new Task<Task>(async () => await foo(),
CancellationToken.None, TaskCreationOptions.LongRunning);
task1.Start();
あなたがそれを待つとき、あなたはそれが返すタスクではなく外側のタスクを待つでしょう。そのため、展開する必要があります。
task1.Unwrap().Wait();
この方法であなたは例外を捕らえるでしょう。しかしながら、これはおそらくない最もよい方法は、Task.Run、async、およびawaitを使用する全体的な理由から、これらの構成要素を避けることでした。 結論として:
task1
- Kevin Gosse.Start()
呼び出すことができません。 - Default
そして、タスクが作成されたらすぐに実行する必要はないので、私はTask.RunではなくTaskコンストラクターを使用しています。
タスクコンストラクタは絶対に使用しないでください。文字通り合理的なユースケースはありませんまったく。
あなたの場合、デリゲートや遅延初期化、あるいはそのようなものは必要ないように思えます。メンバーとメソッドはプライベートなので、実行時にタスクメンバーを割り当てるのと同じくらい意味があります。
private async Task readLoop();
// when the task needs to run:
readTask = Task.Run(() => readLoop());
しかし、あなたが行う現在ではなく将来実行するコードを表す必要がある場合は、デリゲートが必要です。この場合、非同期デリゲート:Func<Task>
:
Func<Task> func = () => Task.Run(() => readLoop());
...
Task task = func();
async
メソッドの戻り値void
これは、呼び出し元のコードが例外を監視できないようにするためです。Task
例外を表すことができるメソッドのため。あなたは使ってはいけませんasync void
この文脈では、そうしないという推奨される方法に従えば、あなたの問題は起こらないでしょう。返品タイプを変更したときにCS0407が表示されるのはなぜでしょうか。あなたは他の場所でも間違いを犯したにちがいありません、しかし、あなたは善を提供しませんでした最小、完全、および検証可能な例それは確実に問題を再現するので、その問題が何であるか、誰も言うことができません。 - Peter Duniho