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

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

ただいまの
回答率

90.37%

  • C#

    9489questions

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

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

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 1,589

kazuya_

score 46

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;
    }
}コード
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+2

こんにちは。

非同期メソッドを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/22 15:30

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

    キャンセル

0

こんにちは。

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/06/21 23:39

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

    キャンセル

  • 2017/06/22 07:40

    例外は非同期処理の中で処理してしまうか、WindowsフォームであればUnhnandledの別スレッド例外が取れたと思うのでその辺りを活用することになるんじゃないかなと思います。

    https://dobon.net/vb/dotnet/programing/unhandledexception.html

    いずれにせよ、何度か投稿されているようなユニットテストはイベントハンドラではなくその中のメソッド単位にするなどスコープを絞られたほうが良いと思います。

    キャンセル

  • 2017/06/22 15:27

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

    キャンセル

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

  • ただいまの回答率 90.37%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • C#

    9489questions

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