注:UnityでC#を使用しています。つまり、バージョン.NET .5であるため、await
またはasync
キーワードを使用できません。
ステートメントを使用動作するメソッドを挿入するとどうなりますか非同期?
_using (WebClient wc = new WebClient()) {
wc.DownloadFileAsync(urlUri, outputFile);
}
SomeMethod1();
SomeMethod2();
_
ご存知のように、メソッドDownloadFileAsync()
が呼び出された後、SomeMethod1()
がまだ-である間にusing
ブロックの外にあるDownloadFileAsync()
が呼び出されます。 作業中。そのため、この場合、usingステートメントと非同期メソッドがどうなるか本当に混乱しています。
wc
のDispose()
は、問題なく適切なタイミングで呼び出されますか?
そうでない場合、この例を修正するにはどうすればよいですか?
コメントから:
では、どうすればこれを回避できますか? awaitキーワードを追加するだけですか?
いいえ、ただそれを行うことはできません。 (そのため、以前に提案された重複質問は実際には重複していませんでした…シナリオは微妙に異なります。)ダウンロードが完了するまで破棄を遅らせる必要がありますが、これはさらに2つのプログラムステートメントを実行する必要があるため複雑です(少なくとも… 良い、最小、完全コード例 )なしで確実に知ることは不可能です。
私doは、待機可能な WebClient.DownloadFileTaskAsync()
メソッドに切り替える必要があると思います。これにより、少なくとも実装が簡素化され、 using
ステートメントを保持します。
返されたTask
オブジェクトをキャプチャし、他のプログラムステートメントが実行される後まで待機しないことで、問題の他の部分に対処できます。
_using (WebClient wc = new WebClient()) {
Task task = wc.DownloadFileTaskAsync(urlUri, outputFile);
SomeMethod1();
SomeMethod2();
await task;
}
_
このようにして、ダウンロードを開始し、他の2つのメソッドを呼び出し、次にコードはダウンロードの完了を待ちます。完了した場合にのみ、using
ブロックが終了し、WebClient
オブジェクトを破棄できるようになります。
もちろん、現在の実装では、間違いなく適切なDownloadXXXCompleted
イベントを処理しています。必要に応じて、その方法でオブジェクトを引き続き使用できます。ただし、IMHOは、await
の使用に切り替えた後、操作の完了時に実行する必要のあるコードをawait
の後に置く方がはるかに優れています。これにより、操作に関連するすべてのコードが1か所に保持され、実装が簡素化されます。
何らかの理由でawait
を使用できない場合は、WebClient
の破棄を遅らせるための代替メカニズムを使用する必要があります。 using
を引き続き使用できるアプローチもあれば、DownloadXXXCompleted
イベントハンドラーでDispose()
を呼び出す必要があるアプローチもあります。より完全なコード例と、await
が適切でない理由の明確な説明がなければ、最良の代替案が何であるかを確実に言うことはできません。
編集:
現在のコードではawait
にアクセスできないことを確認したので、古いコードと互換性のある他のオプションをいくつか示します…
1つの可能性は、操作を開始した後、同じスレッドで待機することです。
_using (WebClient wc = new WebClient()) {
object waitObject = new object();
lock (waitObject)
{
wc.DownloadFileCompleted += (sender, e) =>
{
lock (waitObject) Monitor.Pulse(waitObject);
};
wc.DownloadFileAsync(urlUri, outputFile);
SomeMethod1();
SomeMethod2();
Monitor.Wait(waitObject);
}
}
_
(注:ManualResetEvent
、CountdownEvent
、さらにはSemaphore
および/または「スリム」な同等物など、上記の適切な同期を使用できます。単純さと効率のためにMonitor
を使用します。当然のことながら、読者は好みに合わせて調整できます。同期の手段。Monitor
以外のotherを好む明らかな理由の1つは、他のタイプの同期手法では、DownloadFileCompleted
イベントハンドラー自体が待機をブロックするリスクがないことです。 SomeMethod1()
メソッドとSomeMethod2()
メソッドを完了します。これが重要かどうかは、もちろん、ファイルのダウンロードと比較して、これらのメソッド呼び出しにかかる時間によって異なります。)
ただし、上記は現在のスレッドをブロックします。場合によってはこれで問題ないこともありますが、ほとんどの場合、操作はUIスレッドで開始されており、操作の間、そのスレッドをブロックしないでください。その場合は、using
を完全に省略し、完了イベントハンドラーからDispose()
を呼び出すだけです。
_WebClient wc = new WebClient();
wc.DownloadFileCompleted += (sender, e) =>
{
wc.Dispose();
};
wc.DownloadFileAsync(urlUri, outputFile);
SomeMethod1();
SomeMethod2();
_
System.Net.WebClient
はイベントDownloadFileCompleted
を提供します。そのイベントのハンドラーを追加し、その時点でクライアントを破棄できます。