いつもお世話になっております。
Visual C#2017 , .NET Framework4.7で開発しております。
C#で画面が固まらないような待ちでDoEventsを使っていたソースがあるのですが、
.NET系言語ではあまりDoEventsを使うのは良くないと聞きましたので、
それをawaitで実現するようなソースも作ってみました。
Visual Studioで[ファイル]-[新規作成]-[プロジェクト]で
[Visual C#]を選択し展開、
[Windowsデスクトップ]を選択します。
右側のウィンドウで
[Windwosフォームアプリケーション(.NET Framework)]を選択し、
名前を今回は[DoEventsAwaitTest]とし、
フレームワークは[.NET Framework4.7]としました。
表示されたForm1画面に
Buttonコントロールを1つ貼り付けます。
Form画面のどこかを右クリックして、[コードの表示]をクリックします。
表示された、
Visual
1public Form1() 2{ 3 InitializeComponent(); 4}
の次行に、
DoEventsソースの場合は、以下のソースを貼り付けます。
private void button1_Click(object sender, EventArgs e) { Console.WriteLine("button1_Click開始"); int res = funcB(5000); Console.WriteLine("button1_Clickおわり"); } public int funcA(int nMillisecond) { int res = funcB(nMillisecond); return res; } public int funcB(int nMillisecond) { DoEventsDelay(nMillisecond); Console.WriteLine("funcBおわり"); return 1; } public void DoEventsDelay(int nMillisecond) { System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); sw.Start(); do { if (sw.ElapsedMilliseconds > nMillisecond) break;//タイムアウト Application.DoEvents(); } while (true); sw.Stop(); sw = null; }
awaitソースの場合は、以下のソースを貼り付けます。
private async void button1_Click(object sender, EventArgs e) { Console.WriteLine("button1_Click開始"); Task<int> taskA = funcA(5000); await taskA; Console.WriteLine("button1_Clickおわり"); } public async Task<int> funcA(int nMillisecond) { Task<int> taskB = funcB(nMillisecond); await taskB; return taskB.Result; } public async Task<int> funcB(int nMillisecond) { await Task.Delay(nMillisecond); Console.WriteLine("funcBおわり"); return 1; }
いずれもbutton1をクリックしてから5秒間の待ち中もForm画面は固まらず、ドラッグ可能です。
DoEventsソースの出力ウィンドウ結果は
button1_Click開始 funcBおわり button1_Clickおわり
awaitソースの出力ウィンドウ結果は
button1_Click開始 'DoEventsAwaitTest.exe' (CLR v4.0.30319: DoEventsAwaitTest.exe): 'C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\mscorlib.resources\v4.0_4.0.0.0_ja_b77a5c561934e089\mscorlib.resources.dll' が読み込まれました。モジュールがシンボルなしでビルドされました。 funcBおわり button1_Clickおわり
とどちらもbutton1_Clickイベントプロシージャ内でfuncBが終わるのを待っていることが分かります。
ここでいくつか質問があるのですが、
①awaitでの待ちを使用する場合は、そのプロシージャをの呼び出し元もさらにその呼び出し元も
開始トリガーのプロシージャ(イベントプロシージャあるいはMain)まで
全てasync Task<>~等の形のプロシージャにする必要があるのでしょうか?
②DoEvents()の代わりとして推奨されるべき方法はawaitが一番良いのでしょうか?
https://docs.microsoft.com/ja-jp/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming
も見てみましたが、何となく確信が持てずにいます。
未だTaskやスレッド関係は勉強中なのですが、ご教示のほどよろしくお願いいたします。
回答3件
あなたの回答
tips
プレビュー