質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

解決済

2回答

9537閲覧

private async Taskをボタンに使用した時、イベントハンドラの型をあわせたい

kazuya_

総合スコア78

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

0クリップ

投稿2017/06/21 13:13

private async Task button1_Clickを使用するとthis.button1.Click += new System.EventHandler(this.button1_Click);で型があいません。

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.Threading; namespace PrivateForm { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private async Task button1_Click(object sender, EventArgs e) { try { await LedSwitchTask("1 0"); } catch { throw; } } private async Task<string> LedSwitchTask(string allArg) { var res = await Task.Run(new Func<string>(() => { string chan; chan = allArg.Substring(0, 1); Thread.Sleep(800); return "OK"; })); return res; //ここで確認したい } } }namespace PrivateForm { partial class Form1 { /// <summary> /// 必要なデザイナー変数です。 /// </summary> private System.ComponentModel.IContainer components = null; /// <summary> /// 使用中のリソースをすべてクリーンアップします。 /// </summary> /// <param name="disposing">マネージ リソースを破棄する場合は true を指定し、その他の場合は false を指定します。</param> protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } #region Windows フォーム デザイナーで生成されたコード /// <summary> /// デザイナー サポートに必要なメソッドです。このメソッドの内容を /// コード エディターで変更しないでください。 /// </summary> private void InitializeComponent() { this.button1 = new System.Windows.Forms.Button(); this.SuspendLayout(); // // button1 // this.button1.Location = new System.Drawing.Point(139, 77); this.button1.Name = "button1"; this.button1.Size = new System.Drawing.Size(75, 23); this.button1.TabIndex = 0; this.button1.Text = "button1"; this.button1.UseVisualStyleBackColor = true; //ここで型があいません this.button1.Click += new System.EventHandler(this.button1_Click); // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 14F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(282, 257); this.Controls.Add(this.button1); this.Name = "Form1"; this.Text = "Form1"; this.ResumeLayout(false); } #endregion private System.Windows.Forms.Button button1; } }コード

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

こんにちは。

非同期メソッドをasync voidにすることは基本的に禁止されなければならないのですが、例外が一つだけ存在します。
それが、「ボタン等、UIからイベントとして呼び出されるメソッド」です。今回でいうbutton1_Clickメソッドはまさにそれに該当します。
その理由は、イベントハンドラデリゲートがvoidで終わるメソッドしか受け入れないためです。歴史的な制約によりこのような設計となってしまっています。

つまり、現状からの変更点としては、

  • button1_Clickメソッドをasync voidに変更する
  • LedSwitchTaskメソッドはTask<string>のままにする
  • テストコード等、コードからのbutton1_Clickメソッドの適切な呼び出しは一切できなくなるので、内部のLedSwitchTaskメソッドを直接呼ぶようにする

ということになります。


UIイベントのメソッドは、「UIから直接呼び出される」関係上、

  1. ユーザのアクションによりイベントが起動する
    -> メソッドを呼び出した相手はコードではなくユーザであるとみなせる
  2. 処理を終えたことを「ユーザに」通知する
    -> コードから呼び出されたわけではないのでTaskを返しても意味がない
    -> よって、UIの更新などを起こすことで完了を通知する

という流れをイメージできます。
このイメージが持てたなら、UIイベントの受け皿メソッドがasync voidでも構わない理由が見えてくると思います。

async voidに変更することにより、想定される例外の管理は非同期メソッドの中で全て行わなれければならないことになりますが、これは同期のイベントメソッドでも同様なので、特に負担が増すということはないです。


少し前にasync/awaitの解説を書いていますので、よろしければ参考にどうぞ。話題は若干高度ですが。
Qiita

投稿2017/06/21 23:54

tamoto

総合スコア4103

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kazuya_

2017/06/22 06:30

ありがとうございました。 private async Taskでリフレクションを使用して帰り値を返せない。という質問をしていますが、、もしおわかりになるようでしたら教えてください。WINDOWSフォームで簡単に何度か実験しましたが、不可解です。
guest

0

こんにちは。

これはエラーメッセージのとおり型があってないだけだと思います。
button1_Click は Taskではなくvoidにしてください。

投稿2017/06/21 14:01

Tak1wa

総合スコア4791

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kazuya_

2017/06/21 14:39

ありがとうございます。async voidにすると、一切例外をとれなくなるようなので、方法はないかなと思っています。
Tak1wa

2017/06/21 22:40

例外は非同期処理の中で処理してしまうか、WindowsフォームであればUnhnandledの別スレッド例外が取れたと思うのでその辺りを活用することになるんじゃないかなと思います。 https://dobon.net/vb/dotnet/programing/unhandledexception.html いずれにせよ、何度か投稿されているようなユニットテストはイベントハンドラではなくその中のメソッド単位にするなどスコープを絞られたほうが良いと思います。
kazuya_

2017/06/22 06:27

ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問