C#入門:Actionとイベントを図解で学ぼう
1. はじめに
プログラムを作っていると、「ボタンを押したら処理を実行する」 という動きが欲しくなることがあります。
C#では、これを Action と イベント を使って作ることができます。
この記事では、図解付きでわかりやすく Action とイベントを学んでいきます。
2. まずはシンプルに体験しよう
次のコードをコピーして実行してみましょう。
using System;
class Program
{
class Button
{
public event Action? Clicked;
public void Click()
{
Clicked?.Invoke();
}
}
static void Main()
{
var button = new Button();
button.Clicked += () => Console.WriteLine("ボタンが押されました!");
button.Clicked += () => Console.WriteLine("もうひとつの処理も実行されました!");
button.Click();
}
}
コードの ? は、「この変数(またはイベント)は、値が入っていない(= null)かもしれない」 という意味です。
イベントと null
C# でイベントを作るとき、最初はだれも登録していないので null になります。
public event Action? Clicked;
- Clicked にだれも登録していない → 中身は null
- だれかが += で処理を登録すると → null ではなくなる
Action と Action? の違い
- Action(?なし) … 「必ず何かしらの処理が入っているはず」
- Action?(?あり) … 「処理が入っていない(null)の場合もある」
イベントは最初は「登録なし=null」なので、? をつけるのが正解です。
呼び出すときの安全確認
イベントを呼び出すときは、
Clicked?.Invoke();
と書きます。
これは「もし Clicked が null じゃなければ呼ぶ」という意味です。
(もし null なら何もしません)
まとめ
- ? は「null でもいいよ」という印。
- イベントは最初は null なので Action? とする。
- 呼び出すときは ?.Invoke() で「null じゃなければ呼ぶ」と安全に書ける。
public event Action? Clicked; の event キーワードの有無 には、初心者が混乱しやすい違いがあります。
1. event キーワードあり
public event Action? Clicked;
これは「イベント専用の仕組み」を定義しています。
- 外部からできること
- += で処理を追加する
- -= で処理を削除する
- 外部からできないこと
- Clicked = null; のように直接代入することはできない
- Clicked(); のように直接呼び出すことはできない
つまり「イベントの管理者(このクラスの中のコード)だけが発火できる」「外からは購読(+= / -=)だけ可能」という、安全な使い方に限定されます。
2. event キーワードなし
public Action? Clicked;
こちらは 単なるデリゲート変数 です。
- 外部からも Clicked = …; と直接上書きできてしまう
- 登録していた処理が消えてしまう危険がある
- 外部から Clicked(); を呼び出せてしまう
つまり「イベントっぽいけど、制約がないので事故が起きやすい」です。
3. なぜ event を使うのか?
イベントは「クラスの利用者(外部)が勝手に書き換えられない」ようにしておくのが基本です。
そのため、イベントの定義には必ず event を付けるのが推奨されます。
4. まとめ
- event あり → イベントとして安全に使える(外部は購読だけできる)
- event なし → 単なるデリゲートで、外部から直接代入や呼び出しが可能になってしまう
これは イベントに処理を登録する書き方 です。
1. 「イベントに処理を登録する」とは?
イベント (Clicked) は「ボタンが押されたときに呼ばれる場所」を用意しておくものです。
そこに「この処理をやって!」と登録するのが += です。
2. () => Console.WriteLine(“ボタンが押されました!"); の意味
これは 「ラムダ式」 という書き方です。
- () は「引数がない」という意味
- => は「~したら」という矢印
- Console.WriteLine(“ボタンが押されました!"); は「実際に行う処理」
つまり
() => Console.WriteLine("ボタンが押されました!")
は
「引数なしで呼ばれたら、画面に文字を表示する処理」
をひとまとまりにしたものです。
3. button.Clicked += … の意味
- button.Clicked は「ボタンが押されたときに実行されるイベント」
- += は「処理を追加する」
したがって
button.Clicked += () => Console.WriteLine("ボタンが押されました!");
は 「ボタンが押されたとき、この処理も実行するように登録する」 という意味です。
4. 実行の流れ
- プログラム開始 → イベントにはまだ何も登録されていない
- += で「ボタンが押されたときの処理」を登録する
- button.Click(); が呼ばれると、イベントが発生して登録した処理が実行される
まとめ
- += は「イベントに処理を追加する」
- () => … は「呼ばれたときに実行する処理をひとまとめにしたもの」
- イベントは「ボタンが押された!」を知らせ、登録した処理が順番に実行される
実行結果
ボタンが押されました!
もうひとつの処理も実行されました!
3. 図で見る「イベントの流れ」
ボタンがクリックされると、イベントに登録された処理が順番に呼び出されるイメージです。
イラストの場合

PlantUMLによるシーケンス図

図にするとこういう流れになります:
- ユーザーがボタンをクリック
- Button が Clicked?.Invoke() を実行
- 登録された処理(処理1, 処理2)が順番に呼び出される
4. 実際の書き方(独立クラス)
サンプルではインナークラスにしていましたが、実際は Button を独立させるほうがわかりやすいです。
using System;
class Button
{
public event Action? Clicked;
public void Click()
{
Clicked?.Invoke();
}
}
class Program
{
static void Main()
{
var button = new Button();
button.Clicked += () => Console.WriteLine("ボタンが押されました!");
button.Clicked += () => Console.WriteLine("もうひとつの処理も実行されました!");
button.Click();
}
}
5. 練習問題
- Button に「Hovered」というイベントを追加して、「マウスがボタンに乗ったとき」にメッセージを表示してみよう。
- button.Clicked に3つ以上の処理を登録したら、どの順番で呼ばれるかを確かめてみよう。
- 次のような RunProcess メソッドを作って、Action を渡して実行してみよう。
static void RunProcess(Action action)
{
Console.WriteLine("処理開始");
action();
Console.WriteLine("処理終了");
}
① Button に「Hovered」イベントを追加
EventHandler を使って独自のイベントを追加できます。
using System;
class Button
{
public event Action Clicked;
public event Action Hovered;
public void OnClick() => Clicked?.Invoke();
public void OnHover() => Hovered?.Invoke();
}
class Program
{
static void Main()
{
var button = new Button();
// イベント登録
button.Hovered += () => Console.WriteLine("マウスがボタンに乗りました!");
button.Clicked += () => Console.WriteLine("ボタンがクリックされました!");
// 実行テスト
button.OnHover(); // Hover イベント
button.OnClick(); // Click イベント
}
}
実行結果(例)
マウスがボタンに乗りました!
ボタンがクリックされました!
② Clicked に複数の処理を登録 → 順番を確認
イベントには複数のメソッドを追加できます。その場合、登録した順番に呼ばれます。
using System;
class Button
{
public event Action Clicked;
public void OnClick() => Clicked?.Invoke();
}
class Program
{
static void Main()
{
var button = new Button();
button.Clicked += () => Console.WriteLine("処理1");
button.Clicked += () => Console.WriteLine("処理2");
button.Clicked += () => Console.WriteLine("処理3");
button.OnClick();
}
}
実行結果
処理1
処理2
処理3
③ RunProcess メソッドで Action を渡す
引数に Action を受け取り、前後にメッセージを出して実行するサンプルです。
using System;
class Program
{
static void RunProcess(Action action)
{
Console.WriteLine("処理開始");
action();
Console.WriteLine("処理終了");
}
static void Main()
{
RunProcess(() =>
{
Console.WriteLine("中で行う処理です。");
});
RunProcess(() =>
{
Console.WriteLine("別の処理を実行しています。");
});
}
}
実行結果
処理開始
中で行う処理です。
処理終了
処理開始
別の処理を実行しています。
処理終了
まとめ
- 独自イベントは event Action で追加できる
- イベントハンドラを複数登録した場合、登録順に実行される
- RunProcess に渡すことで、処理の前後に共通処理を差し込める
この3問で、イベントの仕組み と Actionの応用 が理解できます。
6. まとめ
- Action は「処理を入れておける箱」
- a(); で呼び出せる(a.Invoke(); も同じ意味)
- イベントは「ボタンが押されたら登録した処理をまとめて呼ぶ仕組み」
- 図で見ると「ボタン → イベント → 複数の処理」の流れが直感的にわかる
event と += の説明は、実際の .NET WinForms テンプレートにそのまま当てはめられます。ポイントは「イベントに購読(+=)して、イベント発生時にフレームワークが Invoke を代行する」という仕組みです。
1. WinForms プロジェクトのファイル構成
- Program.cs … エントリポイントApplicationConfiguration.Initialize(); → Application.Run(new Form1());
- Form1.cs … フォームの本体。イベントハンドラの中身を書く場所。
- Form1.Designer.cs … Visual Studio デザイナが自動生成。コントロール生成・配置・イベント購読 += のコードがここに入る。→ 手動編集は避けるのが原則。
2. 自動生成されるイベント購読コードの違い
● .NET Framework 時代(古いテンプレート)
this.button1.Click += new System.EventHandler(this.button1_Click);
- this. を明示
- new System.EventHandler(…) を明示
● .NET 6 / 7 / 8 の現行テンプレート
button1.Click += button1_Click;
- this. が省略される
- new EventHandler(…) も省略(メソッドグループ変換で暗黙にキャスト)
👉 意味は完全に同じです。
現在のテンプレートは Roslyn によるコード生成がモダン化され、省略形が標準になっています。
3. Designer と記事コードの対応
記事の例:
button.Clicked += () => Console.WriteLine("処理1");
button.Clicked += () => Console.WriteLine("処理2");
button.Clicked?.Invoke();
WinForms の場合:
- 購読 (+=)→ Form1.Designer.cs 内で button1.Click += button1_Click; が生成される。
- イベント本体→ Form1.cs 内で private void button1_Click(object sender, EventArgs e) が作られる。
- Invoke→ Clicked?.Invoke() は WinForms の内部 (OnClick) が代わりにやってくれる。開発者は直接書かない。
まとめ
- 記事の event/+=/?.Invoke() の仕組みは、WinForms の Click でもそのまま適用できる。
- 違いは「Invoke を自分で呼ばず、WinForms が内部でやってくれる」こと。
- 自動生成される購読コードは
- .NET Framework → this.button1.Click += new System.EventHandler(this.button1_Click);
- .NET 6+ → button1.Click += button1_Click;と書式が異なるが、意味は同じ。
👉 現在の Visual Studio / .NET でプロジェクトを作ると「省略形」で出ます。
昔の記事や教材に「new System.EventHandler(…)」と書いてあっても、内容は同じなので安心してください。
ディスカッション
コメント一覧
まだ、コメントがありません