[C#] 19. 列挙型(enum)を使う方法


Study / C#    作成日付 : 2019/07/11 23:13:25   修正日付 : 2021/08/31 19:42:39

こんにちは。明月です。


この投稿はC#で列挙型(enum)を使う方法に関する説明です。


我々がプログラムを作成する時に、固定値を使う場合があります。その時に変数の定数化(値が変わらない変数)を通って値を定義して使います。

link - [C#] 3. プログラミングの始めと変数と定数を使う方法

using System;

namespace Example
{
  class Program
  {
    // 定数設定
    public const int TYPE1 = 1;
    public const int TYPE2 = 2;
    // 関数呼び出す。
    private static void Print(int type)
    {
      // パラメータ値がTYPE1なら
      if (type == TYPE1)
      {
        // コンソール出力
        Console.WriteLine("Print Type1");
      }
      // パラメータ値がTYPE2なら
      else if (type == TYPE2)
      {
        // コンソール出力
        Console.WriteLine("Print Type2");
      }
      // その以外
      else
      {
        // コンソール出力
        Console.WriteLine("Other");
      }
    }
 
    // 実行関数
    public static void Main(string[] args)
    {
      // 関数呼び出す。
      Print(TYPE1);
 
      // 任意のキーを押してください
      Console.WriteLine("Press any key...");
      Console.ReadLine();
    }
  }
}


上の例をみればPrintという関数のパラメータのタイプがintタイプなのでただ、1や2を入れても問題なく作動します。

でも、実際のプロジェクトでコーディングする際にコード上でただ1や2で作成すると、次でコードを見る時に何の意味が分からない場合があります。それで意味を分かりやすくするために定数に変換して1や2の意味を分かるように作成します。

上の例では私がTYPE1とTYPE2の定数を作成して意味を作ることです。実際にもこのようによく作成しますが、それも可読性の限界があります。

using System;

namespace Example
{
  class Program
  {
    // 定数設定
    // typeAの定数
    public const int ATYPE1 = 1;
    public const int ATYPE2 = 2;
    // typeBの定数
    public const int BTYPE1 = 1;
    public const int BTYPE2 = 2;
    // 関数作成
    private static void Print(int typeA, int typeB)
    {
      // typeAのパラメータ値がATYPE1なら
      if (typeA == ATYPE1)
      {
        // コンソール出力
        Console.WriteLine("Print AType - 1");
      }
      // typeAのパラメータ値がATYPE2なら
      else if (typeA == ATYPE2)
      {
        // コンソール出力
        Console.WriteLine("Print AType - 2");
      }
      // typeBのパラメータ値がBTYPE1なら
      if (typeB == BTYPE1)
      {
        // コンソール出力
        Console.WriteLine("Print BTYPE - 1");
      }
      // typeBのパラメータ値がBTYPE2なら
      else if (typeB == BTYPE2)
      {
        // コンソール出力
        Console.WriteLine("Print BTYPE - 2");
      }
    }
 
    // 実行関数
    public static void Main(string[] args)
    {
      // 関数呼び出す。
      Print(ATYPE1, BTYPE1);
 
      // 任意のキーを押してください
      Console.WriteLine("Press any key...");
      Console.ReadLine();
    }
  }
}


typeAのパラメータにはATYPE1とATYPE2を使ってtypeBのパラメータにはBTYPE1とBTYPE2を使います。

私がソースを読みやすいためにtypeAのパラメータの定数とtypeBのパラメータの定数を区分しておきました。でも、このパラメータのデータタイプはintタイプなので、区分してもtypeAパラメータにもBTYPE1やBTYPE2定数を使っても問題ありません。

でも、そのルールを従って作成しないと、後でソースを解析する立場で意味が可笑しくなります。可読性が悪くなることも当たり前です。


それを整理することが可能にするものが列挙型(enum)です。

using System;

namespace Example
{
  class Program
  {
    // 列挙型 TypeA
    enum TypeA
    {
      TYPE1,
      TYPE2
    }
    // 列挙型 TypeB
    enum TypeB
    {
      TYPE1,
      TYPE2
    }
    // 関数作成
    private static void Print(TypeA typeA, TypeB typeB)
    {
      // typeAのパラメータ値がTYPE1なら
      if (typeA == TypeA.TYPE1)
      {
        // コンソール出力
        Console.WriteLine("Print AType - 1");
      }
      // typeAのパラメータ値がTYPE2なら
      else if (typeA == TypeA.TYPE2)
      {
        // コンソール出力
        Console.WriteLine("Print AType - 2");
      }
      // typeBのパラメータ値がTYPE1なら
      if (typeB == TypeB.TYPE1)
      {
        // コンソール出力
        Console.WriteLine("Print BTYPE - 1");
      }
      // typeBのパラメータ値がTYPE2なら
      else if (typeB == TypeB.TYPE2)
      {
        // コンソール出力
        Console.WriteLine("Print BTYPE - 2");
      }
    }
 
    // 実行関数
    public static void Main(string[] args)
    {
      // 関数呼び出す。
      Print(TypeA.TYPE1, TypeB.TYPE2);
 
      // 任意のキーを押してください
      Console.WriteLine("Press any key...");
      Console.ReadLine();
    }
  }
}


定数を列挙型に纏めてTypeAのパラメータにTypeBを入れることや数の1を入れて間違いコーディングを作成することができないし、可読性が悪くならないことにして、綺麗なソースコードを作成することができます。


列挙型は単純な定数の値を処理することではなく、bit flag値を設定して、もっと読みやすいソースコードを作成することができます。

using System;

namespace Example
{
  class Program
  {
    // ビット演算子の値で設定する。
    enum TypeA
    {
      // 0000 0000
      None = 0x00,
      // 0000 0001
      TYPE1 = 0x01,
      // 0000 0010
      TYPE2 = 0x02,
      // 0000 0100
      TYPE3 = 0x04,
      // 0000 1000
      TYPE4 = 0x08,
      // 0001 0000
      TYPE5 = 0x10,
      // 0010 0000
      TYPE6 = 0x20,
      // 0100 0000
      TYPE7 = 0x40,
      // 1000 0000
      TYPE8 = 0x80
    }
    // 関数作成
    private static void Print(TypeA typeA)
    {
      // typeAのパラメータがTYPE1なら
      if ((typeA & TypeA.TYPE1) != 0)
      {
        // コンソール出力
        Console.WriteLine("Print AType - 1");
      }
      // typeAのパラメータがTYPE2なら
      if ((typeA & TypeA.TYPE2) != 0)
      {
        // コンソール出力
        Console.WriteLine("Print AType - 2");
      }
      // typeAのパラメータがTYPE3なら
      if ((typeA & TypeA.TYPE3) != 0)
      {
        // コンソール出力
        Console.WriteLine("Print AType - 3");
      }
      // typeAのパラメータがTYPE4なら
      if ((typeA & TypeA.TYPE4) != 0)
      {
        // コンソール出力
        Console.WriteLine("Print AType - 4");
      }
      // typeAのパラメータがTYPE5なら
      if ((typeA & TypeA.TYPE5) != 0)
      {
        // コンソール出力
        Console.WriteLine("Print AType - 5");
      }
      // typeAのパラメータがTYPE6なら
      if ((typeA & TypeA.TYPE6) != 0)
      {
        // コンソール出力
        Console.WriteLine("Print AType - 6");
      }
      // typeAのパラメータがTYPE7なら
      if ((typeA & TypeA.TYPE7) != 0)
      {
        // コンソール出力
        Console.WriteLine("Print AType - 7");
      }
      // typeAのパラメータがTYPE8なら
      if ((typeA & TypeA.TYPE8) != 0)
      {
        // コンソール出力
        Console.WriteLine("Print AType - 8");
      }
    }
 
    // 実行関数
    public static void Main(string[] args)
    {
      // 関数呼び出す。
      Print(TypeA.TYPE1 | TypeA.TYPE4 | TypeA.TYPE7);
 
      // 任意のキーを押してください
      Console.WriteLine("Press any key...");
      Console.ReadLine();
    }
  }
}


上の例はビットのTYPE1とTYPE4、TYPE7をOR演算処理してパラメータに渡して、AND演算処理してデータのflag情報を取得することができます。

つまり、一つの変数でflagの情報を格納、取得ができます。

using System;

namespace Example
{
  class Program
  {
    // ビット演算子の値で設定する。
    enum TypeA
    {
      // 0000 0000
      None = 0x00,
      // 0000 0001
      TYPE1 = 0x01,
      // 0000 0010
      TYPE2 = 0x02,
      // 0000 0100
      TYPE3 = 0x04,
      // 0000 1000
      TYPE4 = 0x08,
      // 0001 0000
      TYPE5 = 0x10,
      // 0010 0000
      TYPE6 = 0x20,
      // 0100 0000
      TYPE7 = 0x40,
      // 1000 0000
      TYPE8 = 0x80
    }
    // 作成関数
    private static void Print(TypeA typeA)
    {
      // コンソール出力(TypeAの列挙型をToStringすると列挙型の文字列が出力する。)
      Console.WriteLine(typeA.ToString());
    }
 
    // 実行関数
    public static void Main(string[] args)
    {
      // 関数呼び出す。
      Print(TypeA.TYPE1);
 
      // 任意のキーを押してください
      Console.WriteLine("Press any key...");
      Console.ReadLine();
    }
  }
}


ToString関数を利用すると列挙型の値ではなく、ソースに作成した列挙型の文字が出力します。


私は新入社員の際に先輩からプログラム作成する時に定数、変数の宣言の以外にソースで数字があればハードコーディングだし、設計およびコーディング失敗だと聞きながら学びました。(ハードコーディングというのはソースで数字があることの意味だけではありません。)

そのため、先輩がプログラム作成作業が終わるといつも定数と変数にデータを置換した記憶があります。でも、仕様によりがあるのでソースで数字があることで設計失敗ではありません。少し極端的だったんですね。

つまり、定数に置換することより数字の1のデータがもっと明確な場合もあります。なので仕様によりですね。凄く珍しいですが。


大きいプロジェクトは一人で作成する場合はありません。大きいプロジェクトじゃなくてもハードコーディングが多くなると作成した時期には分かるかも知らないけど、一か月だけ過ぎても分からなくなります。

そのため、ソース可読性は凄く重要です。可読性のため、コメントがありますが、ソースのすべてのところでコメントを付けることもできないし、コメントが多すぎるなら逆にソースが汚くなり、ソース可読性が悪くなります。

なので、ソース可読性のために列挙型は凄く重要な文法と言います。


ここまでC#で列挙型(enum)を使う方法に関する説明でした。


ご不明なところや間違いところがあればコメントしてください。

#C#
最新投稿