基礎から学ぶC#入門 90日コース | 継承・抽象化・インターフェース - Day 47:enum

C# 90日で身につけるC#
スポンサーリンク
スポンサーリンク

Day 47 のゴールと全体像

Day 47 のテーマは enum(列挙型)と状態管理です。

キーワードはこの2つです。

  • 列挙型
  • 状態管理

ここまで、クラス・継承・インターフェース・依存関係と、 「オブジェクトの設計」を中心に見てきましたが、 Day 47 では、

「オブジェクトの“状態”を、わかりやすく・安全に表現する」

ための道具として、enum をじっくり扱っていきます。

列挙型(enum)とは何か

「限られた選択肢を名前で表すための型」

enum(列挙型)は、

「この値は、決められた候補のどれかである」

ということを、 名前付きの定数の集合として表現するための仕組みです。

たとえば、

  • 会員ランク:Bronze, Silver, Gold
  • 注文ステータス:Pending, Processing, Completed, Cancelled
  • アプリの状態:Idle, Running, Paused, Stopped

など、 「限られた選択肢の中からひとつを選ぶ」場面で活躍します。

まずはシンプルな enum を定義してみる

会員ランクを表す MembershipRank

// 会員ランクを表す列挙型
enum MembershipRank
{
    Bronze,   // ブロンズ会員
    Silver,   // シルバー会員
    Gold      // ゴールド会員
}
C#

ここでのポイントは、

  • enum キーワードで列挙型を宣言する
  • 中に「取りうる値」を列挙して書く
  • 各値は、実際には整数(0, 1, 2, …)として扱われますが、 コード上は「名前」で扱える

というところです。

enum を使って状態を持つクラスを作る

会員クラス Member にランクを持たせる

using System;

// 会員クラス
class Member
{
    public string Name { get; set; }

    // 会員ランクを enum で管理する
    public MembershipRank Rank { get; set; }

    public Member(string name, MembershipRank rank)
    {
        Name = name;
        Rank = rank;
    }

    // 会員情報を表示するメソッド
    public void ShowInfo()
    {
        Console.WriteLine($"名前: {Name}");
        Console.WriteLine($"ランク: {Rank}");
    }
}
C#

使う側はこうなります。

class Program
{
    static void Main(string[] args)
    {
        // ゴールド会員を作成
        Member m1 = new Member("山田", MembershipRank.Gold);

        // シルバー会員を作成
        Member m2 = new Member("佐藤", MembershipRank.Silver);

        m1.ShowInfo();
        Console.WriteLine();
        m2.ShowInfo();

        Console.ReadLine();
    }
}
C#

ここで注目してほしいのは、

  • ランクを string ではなく MembershipRank という 専用の型で表現していること
  • MembershipRank.Gold のように、 「名前付きの定数」として扱えること

です。

重要ポイント:

  • enum を使うと、「この値はこの候補のどれかである」ということを 型レベルで表現できるようになります。

enum を使うメリット

1. 間違った値を入れにくくなる

もしランクを string で管理していたら、

Rank = "Goold"; // スペルミス…
Rank = "VIP";   // 想定外の値…
C#

のようなミスが、コンパイル時には検出されません。

一方、MembershipRank を使っていれば、

Rank = MembershipRank.Gold;   // OK
Rank = MembershipRank.Silver; // OK
Rank = (MembershipRank)100;   // こういう変なことは普通は書かない
C#

というふうに、 「定義されていない値」をうっかり入れる可能性がぐっと減ります。

2. コードの意味が読みやすくなる

Rank = MembershipRank.Gold; と書いてあると、

  • 「これは会員ランクであり、その値はゴールドである」

ということが一目で分かります。

Rank = 2; と書いてあるより、 ずっと読みやすいですよね。

3. 状態管理の分岐がわかりやすくなる

switch 文などで状態ごとの処理を分けるときも、 enum はとても役立ちます。

void ShowBenefit(MembershipRank rank)
{
    switch (rank)
    {
        case MembershipRank.Bronze:
            Console.WriteLine("ブロンズ会員特典:ポイント1倍");
            break;

        case MembershipRank.Silver:
            Console.WriteLine("シルバー会員特典:ポイント1.5倍");
            break;

        case MembershipRank.Gold:
            Console.WriteLine("ゴールド会員特典:ポイント2倍+特別クーポン");
            break;
    }
}
C#

このように、 「状態ごとの処理」を書くときに、 enum はコードの意味をとてもクリアにしてくれます。

状態管理に enum を使う実践例

注文ステータスを表す OrderStatus

アプリケーションでは、「状態」を扱う場面がたくさんあります。 その代表例が「注文ステータス」です。

// 注文ステータスを表す列挙型
enum OrderStatus
{
    Pending,    // 受付待ち
    Processing, // 処理中
    Completed,  // 完了
    Cancelled   // キャンセル
}
C#

注文クラス Order

using System;

class Order
{
    public int Id { get; set; }
    public string CustomerName { get; set; }

    // 注文の状態を enum で管理する
    public OrderStatus Status { get; private set; }

    public Order(int id, string customerName)
    {
        Id = id;
        CustomerName = customerName;
        Status = OrderStatus.Pending; // 初期状態は Pending
    }

    // 状態を「処理中」にする
    public void StartProcessing()
    {
        if (Status != OrderStatus.Pending)
        {
            Console.WriteLine("この注文は、すでに処理中または完了・キャンセルされています。");
            return;
        }

        Status = OrderStatus.Processing;
        Console.WriteLine($"注文 {Id} を処理中に変更しました。");
    }

    // 状態を「完了」にする
    public void Complete()
    {
        if (Status != OrderStatus.Processing)
        {
            Console.WriteLine("処理中の注文のみ完了にできます。");
            return;
        }

        Status = OrderStatus.Completed;
        Console.WriteLine($"注文 {Id} を完了に変更しました。");
    }

    // 状態を「キャンセル」にする
    public void Cancel()
    {
        if (Status == OrderStatus.Completed)
        {
            Console.WriteLine("完了した注文はキャンセルできません。");
            return;
        }

        Status = OrderStatus.Cancelled;
        Console.WriteLine($"注文 {Id} をキャンセルに変更しました。");
    }

    // 注文情報を表示する
    public void ShowInfo()
    {
        Console.WriteLine($"注文ID: {Id}");
        Console.WriteLine($"顧客名: {CustomerName}");
        Console.WriteLine($"状態: {Status}");
    }
}
C#

実際に状態を変えてみる

class Program
{
    static void Main(string[] args)
    {
        Order order = new Order(1, "山田太郎");

        order.ShowInfo();
        Console.WriteLine();

        order.StartProcessing();
        order.ShowInfo();
        Console.WriteLine();

        order.Complete();
        order.ShowInfo();
        Console.WriteLine();

        // 完了後にキャンセルしようとしてみる
        order.Cancel();
        order.ShowInfo();

        Console.ReadLine();
    }
}
C#

ここでのポイントは、

  • OrderStatus という enum を使って、 注文の状態を「決められた候補のどれか」に限定していること
  • メソッド内で Status をチェックしながら、 「この状態のときだけ、次の状態に進める」というロジックを書いていること

重要ポイント:

  • enum は「状態の種類」をはっきりさせることで、 状態遷移(状態の変化)のロジックを分かりやすくしてくれます。

enum と switch で状態ごとの処理を整理する

アプリの動作モードを表す AppMode

もうひとつ、アプリの「モード」を例にしてみます。

// アプリの動作モード
enum AppMode
{
    Idle,    // 待機中
    Running, // 実行中
    Paused,  // 一時停止
    Stopped  // 停止
}
C#

モードごとの処理を switch で分ける

using System;

class App
{
    public AppMode Mode { get; private set; } = AppMode.Idle;

    public void ChangeMode(AppMode newMode)
    {
        Mode = newMode;
        Console.WriteLine($"モードを {Mode} に変更しました。");
    }

    public void Execute()
    {
        switch (Mode)
        {
            case AppMode.Idle:
                Console.WriteLine("待機中です。何もしていません。");
                break;

            case AppMode.Running:
                Console.WriteLine("アプリが動作中です。処理を実行しています。");
                break;

            case AppMode.Paused:
                Console.WriteLine("一時停止中です。処理は止まっています。");
                break;

            case AppMode.Stopped:
                Console.WriteLine("停止状態です。アプリは終了しています。");
                break;
        }
    }
}
C#

実行例

class Program
{
    static void Main(string[] args)
    {
        App app = new App();

        app.Execute();
        Console.WriteLine();

        app.ChangeMode(AppMode.Running);
        app.Execute();
        Console.WriteLine();

        app.ChangeMode(AppMode.Paused);
        app.Execute();
        Console.WriteLine();

        app.ChangeMode(AppMode.Stopped);
        app.Execute();

        Console.ReadLine();
    }
}
C#

このように、

  • モードを AppMode という enum で表現し
  • switch で状態ごとのメッセージや処理を分ける

ことで、 「状態管理」がとても見通しのよいコードになります。

enum の基本テンプレート

最後に、 enum を使った状態管理の基本形をテンプレートとしてまとめます。

列挙型の定義

// 状態を表す列挙型
enum TaskStatus
{
    NotStarted, // 未開始
    InProgress, // 進行中
    Done,       // 完了
    Failed      // 失敗
}
C#

状態を持つクラス

using System;

class Task
{
    public string Name { get; set; }
    public TaskStatus Status { get; private set; } = TaskStatus.NotStarted;

    public Task(string name)
    {
        Name = name;
    }

    public void Start()
    {
        if (Status != TaskStatus.NotStarted)
        {
            Console.WriteLine("未開始のタスクのみ開始できます。");
            return;
        }

        Status = TaskStatus.InProgress;
        Console.WriteLine($"タスク「{Name}」を開始しました。");
    }

    public void Complete()
    {
        if (Status != TaskStatus.InProgress)
        {
            Console.WriteLine("進行中のタスクのみ完了できます。");
            return;
        }

        Status = TaskStatus.Done;
        Console.WriteLine($"タスク「{Name}」が完了しました。");
    }

    public void Fail()
    {
        if (Status == TaskStatus.Done)
        {
            Console.WriteLine("完了したタスクは失敗にできません。");
            return;
        }

        Status = TaskStatus.Failed;
        Console.WriteLine($"タスク「{Name}」が失敗しました。");
    }

    public void ShowStatus()
    {
        Console.WriteLine($"タスク名: {Name}, 状態: {Status}");
    }
}
C#

使う側

class Program
{
    static void Main(string[] args)
    {
        Task task = new Task("レポート作成");

        task.ShowStatus();
        task.Start();
        task.ShowStatus();
        task.Complete();
        task.ShowStatus();

        Console.ReadLine();
    }
}
C#

このテンプレートをベースに、

  • 自分のアプリの中で「状態」を持つもの(注文・タスク・画面・接続など)を探し
  • その状態を enum で表現してみる

という練習をすると、 enum と状態管理の感覚がぐっと身近になります。

Day 47 のまとめ

Day 47 では、

  • 列挙型(enum) → 「限られた選択肢」を名前付きの定数として表現する型
  • 状態管理 → オブジェクトの状態を enum で表し、状態ごとの処理や遷移をわかりやすく書くこと

を、会員ランク・注文ステータス・アプリのモード・タスクの状態などの例を通して学びました。

enum は、

「この値は、この候補のどれかである」

ということを、 型としてはっきり宣言できる道具です。

それによって、

  • 間違った値を入れにくくなる
  • コードの意味が読みやすくなる
  • 状態ごとの処理や遷移が整理しやすくなる

という、大きなメリットが生まれます。

ぜひ、

  • 自分のコードの中で「状態」を扱っている場所を探してみる
  • それを enum で表現し直してみる
  • switch やメソッドで状態ごとの処理を整理してみる

という小さな練習を通して、 enum を 「ただの便利機能」ではなく、 状態管理をきれいにするための頼れる相棒として、 少しずつ体に馴染ませていってください。

タイトルとURLをコピーしました