C# enumの使い方を初心者向けに徹底解説|定義・変換・比較・Flagsまでわかる完全ガイド
はじめに
C#でプログラムを書いていると、「状態」「種類」「区分」「権限」など、あらかじめ決まった選択肢の中から値を扱いたい場面がよくあります。
たとえば、注文の状態を表す場合に、次のような数値で管理することもできます。
C#int status = 1;
しかし、これだけでは1が何を意味しているのか分かりにくいです。1が「処理中」なのか、「完了」なのか、「キャンセル」なのかは、コードを読んだだけでは判断できません。
このような場面で役立つのが、C#のenumです。
enumを使うと、数値に分かりやすい名前を付けて扱えるため、コードの可読性が高くなり、入力ミスや管理ミスも減らせます。
この記事では、C#のenumについて、基本的な定義方法から、数値・文字列との変換、比較、一覧取得、Flags属性を使ったビット演算、実践的な設計ポイントまで初心者向けに詳しく解説します。
1. C# enumとは?初心者が最初に押さえるべき基本
1-1. enumは「決まった選択肢」を名前付きで扱うための型
C#のenumは、あらかじめ決められた値の集合を名前付きで定義するための型です。
正式には「列挙型」と呼ばれます。
たとえば、注文状態を表す場合、次のように定義できます。
C#public enum OrderStatus
{
Pending,
Processing,
Completed,
Canceled
}
このように定義すると、注文状態をOrderStatus.PendingやOrderStatus.Completedのように分かりやすい名前で扱えます。
C#OrderStatus status = OrderStatus.Processing;
enumは、内部的には数値を持っています。しかし、コード上では名前で扱えるため、数値を直接書くよりも意味が明確になります。
1-2. enumを使うメリット:可読性・保守性・入力ミス防止
enumを使う大きなメリットは、コードの意味が読み取りやすくなることです。
たとえば、次のコードを見てください。
C#int userType = 2;
この2が何を意味するのかは、コードだけでは分かりません。
一方、enumを使うと次のように書けます。
C#UserType userType = UserType.Admin;
このコードであれば、「ユーザー種別が管理者である」ことがすぐに分かります。
また、enumを使うことで、定義されていない値を誤って入力するリスクも減らせます。文字列で管理する場合は、"Admin"を"Admn"のように打ち間違えてもコンパイル時には気づけないことがあります。
C#string userType = "Admn";
しかし、enumであれば、存在しないメンバー名を指定するとコンパイルエラーになります。
C#UserType userType = UserType.Admn; // エラー
このように、enumは可読性、保守性、安全性を高めるために役立ちます。
1-3. intやstringだけで管理する場合との違い
enumを使わずに、intやstringで状態を管理することもできます。
たとえば、intで管理する場合は次のようになります。
C#int status = 1;
if (status == 1)
{
Console.WriteLine("処理中です");
}
このコードでは、1の意味を別の資料やコメントで確認しなければなりません。
次に、stringで管理する場合です。
C#string status = "Processing";
if (status == "Processing")
{
Console.WriteLine("処理中です");
}
stringは数値より意味が分かりやすいですが、タイプミスに弱いという問題があります。
C#string status = "Procesing"; // Processingのつづり間違い
このようなミスはコンパイル時には検出されにくく、実行時の不具合につながります。
enumを使うと、次のように書けます。
C#OrderStatus status = OrderStatus.Processing;
if (status == OrderStatus.Processing)
{
Console.WriteLine("処理中です");
}
このコードは意味が明確で、存在しない値を使おうとするとコンパイルエラーになるため、安全です。
1-4. enumがよく使われる場面:状態・種類・権限・曜日など
enumは、選択肢があらかじめ決まっている場面でよく使われます。
代表的な例としては、次のようなものがあります。
C#public enum OrderStatus
{
Pending,
Processing,
Completed,
Canceled
}
注文状態の管理に使えます。
C#public enum PaymentType
{
Cash,
CreditCard,
BankTransfer,
ElectronicMoney
}
支払い方法の種類を表せます。
C#public enum UserRole
{
Guest,
Member,
Admin
}
ユーザー権限や役割を表せます。
C#public enum DayOfWeekType
{
Sunday,
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday
}
曜日のように決まった値を扱う場合にも使えます。
このように、enumは「選択肢が固定されているデータ」を扱うときに非常に便利です。
2. C# enumの基本的な定義方法
2-1. enumの基本構文
C#でenumを定義する基本構文は次のとおりです。
C#public enum EnumName
{
Value1,
Value2,
Value3
}
たとえば、注文状態を表すenumは次のように定義できます。
C#public enum OrderStatus
{
Pending,
Processing,
Completed,
Canceled
}
enumはクラスの外側に定義することも、クラスの内側に定義することもできます。
C#public class Order
{
public enum Status
{
Pending,
Processing,
Completed,
Canceled
}
}
ただし、複数のクラスで使い回す場合は、クラスの外側に独立した型として定義することが多いです。
2-2. enum名・メンバー名の命名ルール
C#では、enum名やメンバー名には分かりやすい名前を付けることが大切です。
一般的には、enum名にはパスカルケースを使います。
C#public enum OrderStatus
{
Pending,
Processing,
Completed
}
パスカルケースとは、単語の先頭を大文字にする書き方です。
C#OrderStatus
PaymentType
UserRole
enumのメンバー名も同じくパスカルケースで書くのが一般的です。
C#public enum PaymentType
{
Cash,
CreditCard,
BankTransfer
}
また、enum名は単数形にすることが多いです。
C#public enum UserRole
{
Guest,
Member,
Admin
}
UserRolesのような複数形ではなく、1つの値を表す型としてUserRoleとするほうが自然です。
ただし、Flags属性を使って複数の値を組み合わせるenumでは、複数形の名前が使われることもあります。
C#[Flags]
public enum Permissions
{
None = 0,
Read = 1,
Write = 2,
Delete = 4
}
2-3. enumの値はデフォルトで0から始まる
C#のenumは、何も数値を指定しない場合、最初のメンバーに0が割り当てられます。
C#public enum OrderStatus
{
Pending, // 0
Processing, // 1
Completed, // 2
Canceled // 3
}
次のようにintへ変換すると、内部の数値を確認できます。
C#OrderStatus status = OrderStatus.Completed;
Console.WriteLine((int)status); // 2
enumは名前で扱うことが多いですが、内部的には数値として管理されています。
2-4. enumに任意の数値を割り当てる方法
enumの各メンバーには、任意の数値を明示的に割り当てることができます。
C#public enum OrderStatus
{
Pending = 10,
Processing = 20,
Completed = 30,
Canceled = 40
}
この場合、OrderStatus.Completedをintに変換すると30になります。
C#OrderStatus status = OrderStatus.Completed;
Console.WriteLine((int)status); // 30
一部の値だけを指定することもできます。
C#public enum SampleType
{
A = 1,
B, // 2
C, // 3
D = 10,
E // 11
}
明示的に値を指定したメンバーの次は、その値に1を足した数値になります。
任意の数値を割り当てる場面としては、データベースに保存する値や外部APIの仕様に合わせる場合などがあります。
2-5. enumの基になる型をbyteやlongに変更する方法
C#のenumは、デフォルトではint型を基にしています。
しかし、必要に応じてbyteやlongなどに変更できます。
C#public enum ErrorCode : long
{
None = 0,
NotFound = 10000000000,
Unauthorized = 20000000000
}
byteを使う例は次のとおりです。
C#public enum Level : byte
{
Low = 1,
Medium = 2,
High = 3
}
基になる型として使えるのは、整数型です。
たとえば、byte、short、int、longなどが使えます。stringやdoubleを基になる型にすることはできません。
C#public enum Status : string // エラー
{
Active = "Active"
}
enumに文字列の値を直接持たせることはできないため、画面表示用の文字列が必要な場合は別の方法で対応します。
3. C# enumの基本的な使い方
3-1. enum型の変数を宣言・代入する
enum型の変数は、通常の型と同じように宣言できます。
C#OrderStatus status;
値を代入する場合は、Enum名.メンバー名の形で指定します。
C#OrderStatus status = OrderStatus.Pending;
後から別の値を代入することもできます。
C#status = OrderStatus.Completed;
enumを使うと、変数に何の種類の値が入るのかが明確になります。
C#PaymentType paymentType = PaymentType.CreditCard;
UserRole role = UserRole.Admin;
このように、意味のある型として扱える点がenumの強みです。
3-2. if文でenumを判定する
enumはif文で簡単に判定できます。
C#OrderStatus status = OrderStatus.Completed;
if (status == OrderStatus.Completed)
{
Console.WriteLine("注文は完了しています");
}
複数の条件を判定することもできます。
C#if (status == OrderStatus.Pending || status == OrderStatus.Processing)
{
Console.WriteLine("注文はまだ処理中です");
}
enumを使うことで、条件式の意味が分かりやすくなります。
C#if (status == OrderStatus.Canceled)
{
Console.WriteLine("注文はキャンセルされました");
}
数値だけで比較するよりも、何を判定しているのかが明確です。
3-3. switch文・switch式でenumを分岐する
enumはswitch文との相性が非常に良いです。
C#OrderStatus status = OrderStatus.Processing;
switch (status)
{
case OrderStatus.Pending:
Console.WriteLine("注文受付中です");
break;
case OrderStatus.Processing:
Console.WriteLine("処理中です");
break;
case OrderStatus.Completed:
Console.WriteLine("完了しました");
break;
case OrderStatus.Canceled:
Console.WriteLine("キャンセルされました");
break;
}
C#のswitch式を使うと、より簡潔に書けます。
C#string message = status switch
{
OrderStatus.Pending => "注文受付中です",
OrderStatus.Processing => "処理中です",
OrderStatus.Completed => "完了しました",
OrderStatus.Canceled => "キャンセルされました",
_ => "不明な状態です"
};
Console.WriteLine(message);
switchを使うと、enumの各値に対して処理を分けやすくなります。
3-4. メソッドの引数や戻り値にenumを使う
enumはメソッドの引数として使うことができます。
C#public void PrintStatus(OrderStatus status)
{
Console.WriteLine($"現在の状態: {status}");
}
呼び出し側では、次のように指定します。
C#PrintStatus(OrderStatus.Completed);
戻り値として使うこともできます。
C#public OrderStatus GetOrderStatus(int orderId)
{
return OrderStatus.Processing;
}
メソッドの引数や戻り値にenumを使うと、そのメソッドがどのような種類の値を扱うのかが明確になります。
C#public bool CanCancel(OrderStatus status)
{
return status == OrderStatus.Pending || status == OrderStatus.Processing;
}
このようなコードは、数値や文字列で管理するよりも読みやすくなります。
3-5. クラスやプロパティでenumを使う実践例
enumはクラスのプロパティとしてもよく使われます。
C#public enum OrderStatus
{
Pending,
Processing,
Completed,
Canceled
}
public class Order
{
public int Id { get; set; }
public OrderStatus Status { get; set; }
}
このクラスを使うと、注文情報に状態を持たせることができます。
C#Order order = new Order
{
Id = 1,
Status = OrderStatus.Pending
};
if (order.Status == OrderStatus.Pending)
{
Console.WriteLine("注文は受付中です");
}
プロパティにenumを使うことで、代入できる値の候補が限定されます。
C#order.Status = OrderStatus.Completed;
Visual StudioなどのIDEでは補完も効くため、入力ミスも減らせます。
4. C# enumと数値の変換
4-1. enumをintに変換する方法
enumをintに変換するには、キャストを使います。
C#OrderStatus status = OrderStatus.Completed;
int value = (int)status;
Console.WriteLine(value);
たとえば、次のようなenumがあるとします。
C#public enum OrderStatus
{
Pending = 0,
Processing = 1,
Completed = 2,
Canceled = 3
}
この場合、OrderStatus.Completedをintに変換すると2になります。
C#int value = (int)OrderStatus.Completed;
Console.WriteLine(value); // 2
データベースに数値として保存したい場合や、外部システムと数値コードで連携する場合に使われます。
4-2. intをenumに変換する方法
intをenumに変換する場合もキャストを使います。
C#int value = 2;
OrderStatus status = (OrderStatus)value;
Console.WriteLine(status); // Completed
数値2がOrderStatus.Completedに対応しているため、表示するとCompletedになります。
ただし、この変換には注意点があります。
4-3. 存在しない数値をenumに変換できてしまう注意点
C#では、enumに定義されていない数値でもキャストできてしまいます。
C#int value = 999;
OrderStatus status = (OrderStatus)value;
Console.WriteLine(status); // 999
OrderStatusに999という値が定義されていなくても、エラーにはなりません。
これは初心者が特に注意すべきポイントです。
enumを使っているからといって、必ず定義済みの値だけが入るとは限りません。特に、外部入力、データベース、API、ファイルから数値を受け取る場合は、値が有効かどうかを確認する必要があります。
4-4. Enum.IsDefinedで有効な値か確認する
数値がenumに定義されているか確認するには、Enum.IsDefinedを使います。
C#int value = 2;
if (Enum.IsDefined(typeof(OrderStatus), value))
{
OrderStatus status = (OrderStatus)value;
Console.WriteLine(status);
}
else
{
Console.WriteLine("無効な値です");
}
ジェネリック版を使える環境では、次のようにも書けます。
C#int value = 2;
if (Enum.IsDefined<OrderStatus>((OrderStatus)value))
{
OrderStatus status = (OrderStatus)value;
Console.WriteLine(status);
}
else
{
Console.WriteLine("無効な値です");
}
外部から受け取った数値をenumに変換する場合は、変換前または変換後に有効性を確認するのが安全です。
4-5. 数値変換を使うべき場面と避けるべき場面
enumと数値の変換は便利ですが、むやみに使うべきではありません。
使うべき場面としては、次のようなケースがあります。
データベースに数値として保存する場合。
C#int dbValue = (int)OrderStatus.Completed;
外部APIの仕様で数値コードが決まっている場合。
C#OrderStatus status = (OrderStatus)apiStatusCode;
ログやファイルに数値として記録する必要がある場合。
一方、通常の業務ロジックでは、できるだけenumの名前で扱うほうが安全です。
C#if (status == OrderStatus.Completed)
{
Console.WriteLine("完了処理を行います");
}
次のように数値で比較するのは避けたほうがよいです。
C#if ((int)status == 2)
{
Console.WriteLine("完了処理を行います");
}
この書き方では、2の意味が分かりにくくなります。
5. C# enumと文字列の変換
5-1. enumを文字列に変換する方法
enumを文字列に変換するには、ToString()を使います。
C#OrderStatus status = OrderStatus.Completed;
string text = status.ToString();
Console.WriteLine(text); // Completed
文字列補間でも自動的に文字列として扱われます。
C#Console.WriteLine($"現在の状態は {status} です");
この場合、出力は次のようになります。
C#現在の状態は Completed です
ただし、ToString()で得られる文字列は、enumのメンバー名です。画面に表示する日本語名とは別に考える必要があります。
5-2. 文字列をenumに変換するEnum.Parseの使い方
文字列をenumに変換するには、Enum.Parseを使います。
C#string text = "Completed";
OrderStatus status = (OrderStatus)Enum.Parse(typeof(OrderStatus), text);
Console.WriteLine(status); // Completed
ジェネリック版を使うと、より簡潔に書けます。
C#string text = "Completed";
OrderStatus status = Enum.Parse<OrderStatus>(text);
Console.WriteLine(status); // Completed
ただし、Enum.Parseは変換できない文字列を渡すと例外が発生します。
C#string text = "Complete";
OrderStatus status = Enum.Parse<OrderStatus>(text); // 例外
ユーザー入力や外部データを扱う場合は、Enum.ParseよりもEnum.TryParseを使うほうが安全です。
5-3. 例外を避けるEnum.TryParseの使い方
Enum.TryParseを使うと、変換に成功したかどうかをboolで判定できます。
C#string text = "Completed";
if (Enum.TryParse<OrderStatus>(text, out OrderStatus status))
{
Console.WriteLine($"変換成功: {status}");
}
else
{
Console.WriteLine("変換できませんでした");
}
Enum.TryParseは、変換できない場合でも例外を発生させません。
C#string text = "Complete";
if (Enum.TryParse<OrderStatus>(text, out OrderStatus status))
{
Console.WriteLine(status);
}
else
{
Console.WriteLine("無効な文字列です");
}
ユーザーが入力した文字列、CSVファイル、JSON、APIレスポンスなどをenumに変換する場合は、TryParseを使うのが基本です。
5-4. 大文字・小文字を無視して変換する方法
Enum.TryParseでは、大文字・小文字を無視して変換できます。
C#string text = "completed";
if (Enum.TryParse<OrderStatus>(text, ignoreCase: true, out OrderStatus status))
{
Console.WriteLine(status); // Completed
}
else
{
Console.WriteLine("変換できませんでした");
}
ignoreCase: trueを指定すると、"Completed"、"completed"、"COMPLETED"などを同じように扱えます。
C#Enum.TryParse<OrderStatus>("COMPLETED", true, out OrderStatus status);
外部入力では大文字・小文字が統一されていないこともあるため、必要に応じてignoreCaseを使うと便利です。
5-5. 日本語表示名や画面表示用の文字列を扱う方法
enumのメンバー名は英語で定義することが多いですが、画面には日本語で表示したい場合があります。
たとえば、次のようなenumがあるとします。
C#public enum OrderStatus
{
Pending,
Processing,
Completed,
Canceled
}
画面には「受付中」「処理中」「完了」「キャンセル」と表示したい場合、switch式で変換する方法があります。
C#public static string ToDisplayName(OrderStatus status)
{
return status switch
{
OrderStatus.Pending => "受付中",
OrderStatus.Processing => "処理中",
OrderStatus.Completed => "完了",
OrderStatus.Canceled => "キャンセル",
_ => "不明"
};
}
使い方は次のとおりです。
C#OrderStatus status = OrderStatus.Completed;
Console.WriteLine(ToDisplayName(status)); // 完了
属性を使って表示名を持たせる方法もあります。
C#using System.ComponentModel.DataAnnotations;
public enum OrderStatus
{
[Display(Name = "受付中")]
Pending,
[Display(Name = "処理中")]
Processing,
[Display(Name = "完了")]
Completed,
[Display(Name = "キャンセル")]
Canceled
}
ただし、属性から値を取り出すにはリフレクションが必要になります。初心者のうちは、まずswitch式や辞書を使った変換から始めると分かりやすいです。
6. C# enumの一覧取得とループ処理
6-1. Enum.GetValuesでenumの値一覧を取得する
Enum.GetValuesを使うと、enumに定義されている値の一覧を取得できます。
C#foreach (OrderStatus status in Enum.GetValues(typeof(OrderStatus)))
{
Console.WriteLine(status);
}
出力例は次のようになります。
C#Pending
Processing
Completed
Canceled
ジェネリック版を使える環境では、次のように書けます。
C#foreach (OrderStatus status in Enum.GetValues<OrderStatus>())
{
Console.WriteLine(status);
}
Enum.GetValuesは、画面の選択肢を作るときや、全てのenum値に対して処理をしたいときに便利です。
6-2. Enum.GetNamesでenum名の一覧を取得する
Enum.GetNamesを使うと、enumのメンバー名を文字列の配列として取得できます。
C#string[] names = Enum.GetNames(typeof(OrderStatus));
foreach (string name in names)
{
Console.WriteLine(name);
}
出力例は次のとおりです。
C#Pending
Processing
Completed
Canceled
ジェネリック版では次のように書けます。
C#string[] names = Enum.GetNames<OrderStatus>();
Enum.GetValuesはenumの値を取得し、Enum.GetNamesは名前の文字列を取得する、という違いがあります。
6-3. foreachでenumを順番に処理する
Enum.GetValuesとforeachを組み合わせると、enumの各値を順番に処理できます。
C#foreach (OrderStatus status in Enum.GetValues<OrderStatus>())
{
string displayName = status switch
{
OrderStatus.Pending => "受付中",
OrderStatus.Processing => "処理中",
OrderStatus.Completed => "完了",
OrderStatus.Canceled => "キャンセル",
_ => "不明"
};
Console.WriteLine($"{status}: {displayName}");
}
出力例は次のようになります。
C#Pending: 受付中
Processing: 処理中
Completed: 完了
Canceled: キャンセル
この方法は、マスターデータのような簡単な選択肢を生成するときに便利です。
6-4. ドロップダウンや選択肢生成にenumを使う例
Webアプリやデスクトップアプリでは、enumからドロップダウンの選択肢を作ることがあります。
たとえば、次のような選択肢用クラスを用意します。
C#public class SelectOption
{
public int Value { get; set; }
public string Text { get; set; } = "";
}
enumから選択肢を作る処理は次のように書けます。
C#List<SelectOption> options = Enum.GetValues<OrderStatus>()
.Select(status => new SelectOption
{
Value = (int)status,
Text = ToDisplayName(status)
})
.ToList();
表示名を返すメソッドは次のように用意します。
C#public static string ToDisplayName(OrderStatus status)
{
return status switch
{
OrderStatus.Pending => "受付中",
OrderStatus.Processing => "処理中",
OrderStatus.Completed => "完了",
OrderStatus.Canceled => "キャンセル",
_ => "不明"
};
}
これにより、enumの定義を元に選択肢を生成できます。
6-5. enum一覧取得時の型変換の注意点
古い書き方では、Enum.GetValues(typeof(OrderStatus))の戻り値は配列として扱われるため、foreachで型を明示する必要があります。
C#foreach (OrderStatus status in Enum.GetValues(typeof(OrderStatus)))
{
Console.WriteLine(status);
}
ジェネリック版を使える場合は、こちらのほうが型安全です。
C#foreach (OrderStatus status in Enum.GetValues<OrderStatus>())
{
Console.WriteLine(status);
}
また、enumに同じ数値を持つメンバーを定義している場合、一覧取得や文字列変換で思わぬ結果になることがあります。
C#public enum SampleStatus
{
None = 0,
Unknown = 0,
Active = 1
}
このような定義は意図が明確でない限り避けたほうがよいです。
7. C# enumの比較方法
7-1. enum同士を==で比較する
enum同士は==で比較できます。
C#OrderStatus status = OrderStatus.Completed;
if (status == OrderStatus.Completed)
{
Console.WriteLine("完了しています");
}
一致しないことを確認する場合は!=を使います。
C#if (status != OrderStatus.Canceled)
{
Console.WriteLine("キャンセルされていません");
}
enumは値型なので、同じenum型同士であればシンプルに比較できます。
7-2. enumと数値を比較するときの注意点
enumと数値を比較したい場合、キャストすれば比較できます。
C#OrderStatus status = OrderStatus.Completed;
if ((int)status == 2)
{
Console.WriteLine("完了です");
}
しかし、この書き方はおすすめできません。
2が何を意味するのか分かりにくくなるためです。
次のようにenumの名前で比較するほうが読みやすくなります。
C#if (status == OrderStatus.Completed)
{
Console.WriteLine("完了です");
}
数値比較が必要になるのは、データベースや外部APIと連携する場面などに限定したほうがよいです。
7-3. enumの大小比較はできるのか
enumは内部的には数値を持っているため、キャストすれば大小比較できます。
C#OrderStatus status = OrderStatus.Processing;
if ((int)status > (int)OrderStatus.Pending)
{
Console.WriteLine("受付後の状態です");
}
ただし、enumの順番や数値に業務的な意味があるとは限りません。
たとえば、次のような定義では大小比較に意味があるかもしれません。
C#public enum Priority
{
Low = 1,
Medium = 2,
High = 3
}
この場合、HighはMediumより優先度が高いと考えられます。
C#if (Priority.High > Priority.Medium)
{
Console.WriteLine("Highのほうが優先度が高いです");
}
ただし、状態を表すenumでは、大小比較よりも明示的な条件分岐のほうが安全です。
C#if (status == OrderStatus.Completed)
{
Console.WriteLine("完了処理を行います");
}
7-4. nullable enumを比較する方法
enumは値型なので、通常はnullを代入できません。
C#OrderStatus status = null; // エラー
nullを許可したい場合は、nullable enumを使います。
C#OrderStatus? status = null;
値があるかどうかを確認するには、HasValueを使います。
C#if (status.HasValue)
{
Console.WriteLine(status.Value);
}
else
{
Console.WriteLine("状態が未設定です");
}
特定の値と比較する場合は、そのまま比較できます。
C#if (status == OrderStatus.Completed)
{
Console.WriteLine("完了しています");
}
statusがnullの場合、この条件はfalseになります。
未設定を表すためにnullable enumを使うこともできますが、多くの場合はUnknownやNoneを定義するほうが扱いやすいです。
C#public enum OrderStatus
{
Unknown = 0,
Pending = 1,
Processing = 2,
Completed = 3,
Canceled = 4
}
7-5. 比較処理で起きやすいミスと対策
enumの比較でよくあるミスは、数値で比較してしまうことです。
C#if ((int)status == 3)
{
Console.WriteLine("完了");
}
このコードは、後からenumの数値が変わったときに壊れやすくなります。
対策として、必ず名前で比較します。
C#if (status == OrderStatus.Completed)
{
Console.WriteLine("完了");
}
もう1つのミスは、外部から受け取った数値を検証せずに使うことです。
C#OrderStatus status = (OrderStatus)999;
このような値が入ると、switch文で想定外の動作をする可能性があります。
対策として、Enum.IsDefinedで検証します。
C#if (!Enum.IsDefined<OrderStatus>(status))
{
throw new ArgumentException("無効な注文状態です");
}
また、新しいenum値を追加したのに、比較処理やswitch文に反映し忘れることもあります。switch式で_を使う場合でも、ログを出すなどして想定外の値に気づけるようにしておくと安全です。
8. C# enumのFlags属性とビット演算
8-1. Flags属性とは?複数の値を組み合わせる仕組み
通常のenumは、基本的に1つの値を選ぶために使います。
C#UserRole role = UserRole.Admin;
一方で、複数の選択肢を組み合わせたい場合があります。
たとえば、ユーザー権限として「読み取り」「書き込み」「削除」を組み合わせたい場合です。
このようなときに使うのがFlags属性です。
C#[Flags]
public enum Permissions
{
None = 0,
Read = 1,
Write = 2,
Delete = 4
}
Flags属性を付けることで、複数の値をビット演算で組み合わせる意図を明確にできます。
C#Permissions permissions = Permissions.Read | Permissions.Write;
この例では、ReadとWriteの権限を同時に持つことを表しています。
8-2. Flags enumの定義方法
Flags enumは、enumの上に[Flags]属性を付けて定義します。
C#[Flags]
public enum Permissions
{
None = 0,
Read = 1,
Write = 2,
Delete = 4,
Execute = 8
}
None = 0は、何の権限も持っていない状態を表します。
C#Permissions permissions = Permissions.None;
複数の権限を組み合わせる場合は、OR演算子|を使います。
C#Permissions permissions = Permissions.Read | Permissions.Write;
Flags属性を付けておくと、ToString()したときにも分かりやすく表示されます。
C#Console.WriteLine(permissions); // Read, Write
8-3. 値を1, 2, 4, 8のように定義する理由
Flags enumでは、値を1, 2, 4, 8のように定義します。
これは、それぞれの値を2進数で見たときに、異なるビットを表すためです。
C#Read = 1 // 0001
Write = 2 // 0010
Delete = 4 // 0100
Execute = 8 // 1000
このように定義することで、複数の値を重ならずに組み合わせることができます。
たとえば、Read | Writeは次のようになります。
C#0001
0010
----
0011
結果は3ですが、ビットを見るとReadとWriteを持っていることが分かります。
もし、次のように連番で定義してしまうと問題が起きます。
C#[Flags]
public enum BadPermissions
{
None = 0,
Read = 1,
Write = 2,
Delete = 3
}
Delete = 3は2進数では0011なので、Read | Writeと同じ値になってしまいます。これでは正しく判定できません。
そのため、Flags enumでは必ず1, 2, 4, 8, 16のように2の累乗で定義します。
8-4. 複数のフラグをORで組み合わせる
複数のフラグを組み合わせるには、OR演算子|を使います。
C#Permissions permissions = Permissions.Read | Permissions.Write;
この変数は、読み取り権限と書き込み権限を持っている状態です。
さらに権限を追加することもできます。
C#permissions = permissions | Permissions.Delete;
短く書くと次のようになります。
C#permissions |= Permissions.Delete;
これで、Read、Write、Deleteの3つの権限を持つ状態になります。
C#Console.WriteLine(permissions); // Read, Write, Delete
よく使う組み合わせを定義しておくこともできます。
C#[Flags]
public enum Permissions
{
None = 0,
Read = 1,
Write = 2,
Delete = 4,
All = Read | Write | Delete
}
このようにすると、全権限を簡単に指定できます。
C#Permissions permissions = Permissions.All;
8-5. HasFlagでフラグを持っているか判定する
特定のフラグを持っているか確認するには、HasFlagを使えます。
C#Permissions permissions = Permissions.Read | Permissions.Write;
if (permissions.HasFlag(Permissions.Read))
{
Console.WriteLine("読み取り権限があります");
}
Writeを持っているか確認する場合は次のようにします。
C#if (permissions.HasFlag(Permissions.Write))
{
Console.WriteLine("書き込み権限があります");
}
持っていない権限の場合はfalseになります。
C#if (permissions.HasFlag(Permissions.Delete))
{
Console.WriteLine("削除権限があります");
}
else
{
Console.WriteLine("削除権限はありません");
}
HasFlagは読みやすいため、初心者にも分かりやすい方法です。
8-6. AND・OR・NOTを使ったフラグ操作
Flags enumでは、ビット演算を使ってフラグを操作できます。
フラグを追加するにはOR演算子|を使います。
C#permissions |= Permissions.Delete;
フラグを持っているか確認するにはAND演算子&を使います。
C#if ((permissions & Permissions.Read) == Permissions.Read)
{
Console.WriteLine("読み取り権限があります");
}
フラグを削除するには、AND演算子&とNOT演算子~を組み合わせます。
C#permissions &= ~Permissions.Write;
これは「Write以外を残す」という意味です。
C#Permissions permissions = Permissions.Read | Permissions.Write | Permissions.Delete;
permissions &= ~Permissions.Write;
Console.WriteLine(permissions); // Read, Delete
フラグを反転させる場合にも~を使いますが、意図しないビットまで立つことがあるため、扱いには注意が必要です。
8-7. Flagsを使うべき場面と使わないほうがよい場面
Flagsを使うべきなのは、複数の値を同時に持つことが自然な場合です。
たとえば、ユーザー権限はFlagsに向いています。
C#Permissions permissions = Permissions.Read | Permissions.Write;
ファイル属性のように、複数の属性を同時に持つものも向いています。
一方、注文状態のように、基本的に1つの状態しか持たないものにはFlagsを使うべきではありません。
C#OrderStatus status = OrderStatus.Pending;
注文が「受付中」でありながら同時に「完了」でもある、という状態は通常は不自然です。
このような場合は、通常のenumを使います。
C#public enum OrderStatus
{
Pending,
Processing,
Completed,
Canceled
}
Flagsは便利ですが、何でもFlagsにすればよいわけではありません。「複数同時に成立するかどうか」を基準に判断しましょう。
9. C# enumを使うときの実践的な設計ポイント
9-1. enumにするべきデータ・しないほうがよいデータ
enumに向いているのは、選択肢が固定されていて、頻繁に増減しないデータです。
たとえば、次のようなものはenumに向いています。
C#public enum OrderStatus
{
Pending,
Processing,
Completed,
Canceled
}
C#public enum Gender
{
Unknown,
Male,
Female,
Other
}
C#public enum LogLevel
{
Debug,
Info,
Warning,
Error
}
一方、頻繁に追加・変更されるデータはenumに向いていません。
たとえば、商品カテゴリ、部署一覧、店舗一覧、キャンペーン種別などは、運用中に変更される可能性があります。
このようなデータは、データベースで管理するほうが向いています。
enumはコードに埋め込まれるため、値を追加・変更するにはプログラムの修正と再リリースが必要になります。
9-2. 0番目の値をNoneやUnknownにする理由
C#のenumの初期値は0です。
そのため、0に意味のある値を割り当てておくことが重要です。
C#public enum OrderStatus
{
Unknown = 0,
Pending = 1,
Processing = 2,
Completed = 3,
Canceled = 4
}
Unknownを用意しておくと、未設定や不明な状態を表せます。
Flags enumの場合は、None = 0を定義するのが一般的です。
C#[Flags]
public enum Permissions
{
None = 0,
Read = 1,
Write = 2,
Delete = 4
}
0を定義していないと、初期値がどのメンバーにも対応しない状態になることがあります。
C#public enum OrderStatus
{
Pending = 1,
Processing = 2,
Completed = 3
}
OrderStatus status = default;
Console.WriteLine(status); // 0
このように、defaultの結果が定義されていない値になる可能性があります。
9-3. enumのメンバーを後から追加するときの注意点
enumに新しいメンバーを追加するときは、その値を使っている処理も一緒に確認する必要があります。
たとえば、次のenumにReturnedを追加したとします。
C#public enum OrderStatus
{
Unknown = 0,
Pending = 1,
Processing = 2,
Completed = 3,
Canceled = 4,
Returned = 5
}
この場合、switch文や表示名変換の処理も更新しなければなりません。
C#public static string ToDisplayName(OrderStatus status)
{
return status switch
{
OrderStatus.Unknown => "不明",
OrderStatus.Pending => "受付中",
OrderStatus.Processing => "処理中",
OrderStatus.Completed => "完了",
OrderStatus.Canceled => "キャンセル",
OrderStatus.Returned => "返品",
_ => "不明"
};
}
追加したenum値を処理し忘れると、画面表示や業務ロジックが正しく動かなくなる可能性があります。
また、既存の数値を変更する場合は特に注意が必要です。データベースに保存済みの値や、外部APIと連携している値がある場合、数値を変更すると過去データの意味が変わってしまいます。
9-4. DB保存・API連携でenumを扱うときの注意点
enumをデータベースに保存する場合、数値で保存する方法と文字列で保存する方法があります。
数値で保存する場合は、容量が小さく、処理もしやすいです。
C#int statusValue = (int)OrderStatus.Completed;
ただし、enumの数値を後から変更すると、保存済みデータの意味が変わる可能性があります。
文字列で保存する場合は、意味が分かりやすいです。
C#string statusText = OrderStatus.Completed.ToString();
しかし、enumのメンバー名を変更すると、過去データと一致しなくなる可能性があります。
API連携でも同じです。外部システムと数値コードや文字列コードを共有する場合は、勝手に値を変えないようにする必要があります。
実務では、enumの内部名と外部連携用の値を分ける設計もよく使われます。
C#public static string ToApiValue(OrderStatus status)
{
return status switch
{
OrderStatus.Pending => "pending",
OrderStatus.Processing => "processing",
OrderStatus.Completed => "completed",
OrderStatus.Canceled => "canceled",
_ => "unknown"
};
}
このようにしておくと、C#側の名前とAPIの値を分けて管理できます。
9-5. enumと定数クラス・Dictionary・クラス設計の使い分け
enumは便利ですが、すべての定数管理に向いているわけではありません。
固定された選択肢を表すならenumが向いています。
C#public enum LogLevel
{
Debug,
Info,
Warning,
Error
}
単純な文字列定数を管理したいだけなら、定数クラスが向いている場合もあります。
C#public static class ApiStatus
{
public const string Success = "success";
public const string Error = "error";
}
表示名や説明文など、値に付随する情報が多い場合は、Dictionaryを使う方法もあります。
C#private static readonly Dictionary<OrderStatus, string> DisplayNames = new()
{
{ OrderStatus.Pending, "受付中" },
{ OrderStatus.Processing, "処理中" },
{ OrderStatus.Completed, "完了" },
{ OrderStatus.Canceled, "キャンセル" }
};
さらに、選択肢ごとに振る舞いや複雑な情報を持たせたい場合は、クラスとして設計したほうがよいこともあります。
C#public class PaymentMethod
{
public string Code { get; }
public string DisplayName { get; }
public PaymentMethod(string code, string displayName)
{
Code = code;
DisplayName = displayName;
}
}
判断基準としては、「単純な固定選択肢ならenum」「文字列コード中心なら定数」「付加情報が多いならDictionaryやクラス」と考えると分かりやすいです。
10. C# enumでよくあるエラーと対処法
10-1. 文字列からenumに変換できない
文字列からenumに変換できない原因として多いのは、文字列がメンバー名と一致していないことです。
C#string text = "complete";
OrderStatus status = Enum.Parse<OrderStatus>(text); // 例外
Enum.Parseは、通常、大文字・小文字の違いも区別します。
対策として、Enum.TryParseで安全に変換します。
C#string text = "complete";
if (Enum.TryParse<OrderStatus>(text, ignoreCase: true, out OrderStatus status))
{
Console.WriteLine(status);
}
else
{
Console.WriteLine("変換できませんでした");
}
また、日本語の表示名から直接変換しようとして失敗するケースもあります。
C#string text = "完了";
Enum.TryParse<OrderStatus>(text, out OrderStatus status); // 基本的には変換できない
この場合は、日本語表示名とenumを対応付ける処理を別途用意します。
C#public static bool TryFromDisplayName(string text, out OrderStatus status)
{
status = text switch
{
"受付中" => OrderStatus.Pending,
"処理中" => OrderStatus.Processing,
"完了" => OrderStatus.Completed,
"キャンセル" => OrderStatus.Canceled,
_ => OrderStatus.Unknown
};
return status != OrderStatus.Unknown;
}
10-2. 想定外の数値がenumに入ってしまう
C#では、定義されていない数値でもenumにキャストできます。
C#OrderStatus status = (OrderStatus)999;
この状態でswitch文を使うと、どのcaseにも一致しないことがあります。
C#switch (status)
{
case OrderStatus.Pending:
Console.WriteLine("受付中");
break;
case OrderStatus.Completed:
Console.WriteLine("完了");
break;
default:
Console.WriteLine("不明な状態");
break;
}
対策として、外部から受け取った数値はEnum.IsDefinedで確認します。
C#int value = 999;
if (!Enum.IsDefined(typeof(OrderStatus), value))
{
Console.WriteLine("無効な値です");
}
else
{
OrderStatus status = (OrderStatus)value;
Console.WriteLine(status);
}
特に、API、DB、ユーザー入力から取得した値は信頼しすぎないことが大切です。
10-3. Flagsの判定結果が期待通りにならない
Flags enumで判定結果が期待通りにならない場合、値の定義が間違っていることがあります。
悪い例は次のとおりです。
C#[Flags]
public enum Permissions
{
None = 0,
Read = 1,
Write = 2,
Delete = 3
}
Delete = 3は、Read | Writeと同じ値になってしまいます。
正しくは、2の累乗で定義します。
C#[Flags]
public enum Permissions
{
None = 0,
Read = 1,
Write = 2,
Delete = 4,
Execute = 8
}
また、複数フラグの判定で==だけを使うと失敗することがあります。
C#Permissions permissions = Permissions.Read | Permissions.Write;
if (permissions == Permissions.Read)
{
Console.WriteLine("読み取り権限があります");
}
この条件はfalseです。なぜなら、permissionsにはReadだけでなくWriteも含まれているからです。
正しくは、HasFlagまたはAND演算を使います。
C#if (permissions.HasFlag(Permissions.Read))
{
Console.WriteLine("読み取り権限があります");
}
10-4. switchで新しいenum値を処理し忘れる
enumに新しい値を追加したとき、switch文の更新を忘れることがあります。
C#public enum OrderStatus
{
Pending,
Processing,
Completed,
Canceled,
Returned
}
しかし、表示名変換ではReturnedを処理していない場合があります。
C#public static string ToDisplayName(OrderStatus status)
{
return status switch
{
OrderStatus.Pending => "受付中",
OrderStatus.Processing => "処理中",
OrderStatus.Completed => "完了",
OrderStatus.Canceled => "キャンセル",
_ => "不明"
};
}
この場合、Returnedは「不明」と表示されてしまいます。
対策として、enum値を追加したら、関連するswitch文、表示名変換、DB変換、API変換、テストコードを確認します。
また、想定外の値が来た場合にログを出す設計にしておくと、不具合に気づきやすくなります。
10-5. enumの表示名を変更したら処理が壊れる
enum.ToString()の結果を画面表示だけでなく、保存値や判定処理にも使っていると、メンバー名を変更したときに処理が壊れることがあります。
C#string status = OrderStatus.Completed.ToString(); // "Completed"
後からCompletedをDoneに変更すると、保存済みの"Completed"と一致しなくなる可能性があります。
このような問題を避けるには、画面表示用、保存用、API連携用の値を分けて管理します。
C#public static string ToDisplayName(OrderStatus status)
{
return status switch
{
OrderStatus.Completed => "完了",
_ => "不明"
};
}
public static string ToApiValue(OrderStatus status)
{
return status switch
{
OrderStatus.Completed => "completed",
_ => "unknown"
};
}
enumのメンバー名をそのまま外部仕様に使うと変更に弱くなるため、実務では変換層を用意するのがおすすめです。
11. C# enumのサンプルコード集
11-1. 状態管理にenumを使うサンプル
注文状態をenumで管理するサンプルです。
C#public enum OrderStatus
{
Unknown = 0,
Pending = 1,
Processing = 2,
Completed = 3,
Canceled = 4
}
public class Order
{
public int Id { get; set; }
public OrderStatus Status { get; set; }
}
public class OrderService
{
public void Complete(Order order)
{
if (order.Status == OrderStatus.Canceled)
{
Console.WriteLine("キャンセル済みの注文は完了できません");
return;
}
order.Status = OrderStatus.Completed;
Console.WriteLine("注文を完了しました");
}
}
使い方は次のとおりです。
C#Order order = new Order
{
Id = 1,
Status = OrderStatus.Processing
};
OrderService service = new OrderService();
service.Complete(order);
Console.WriteLine(order.Status); // Completed
数値や文字列で状態を管理するよりも、意味が分かりやすくなります。
11-2. ユーザー権限をFlags enumで管理するサンプル
複数の権限を持たせたい場合は、Flags enumが便利です。
C#[Flags]
public enum Permissions
{
None = 0,
Read = 1,
Write = 2,
Delete = 4,
Admin = 8
}
public class User
{
public string Name { get; set; } = "";
public Permissions Permissions { get; set; }
}
使い方は次のとおりです。
C#User user = new User
{
Name = "Taro",
Permissions = Permissions.Read | Permissions.Write
};
if (user.Permissions.HasFlag(Permissions.Read))
{
Console.WriteLine("読み取り可能です");
}
if (!user.Permissions.HasFlag(Permissions.Delete))
{
Console.WriteLine("削除権限はありません");
}
権限を追加する場合は、OR演算子を使います。
C#user.Permissions |= Permissions.Delete;
権限を削除する場合は、ANDとNOTを使います。
C#user.Permissions &= ~Permissions.Write;
このように、Flags enumを使うと複数権限を1つの値で管理できます。
11-3. 文字列入力をenumに安全に変換するサンプル
ユーザー入力や外部データをenumに変換する場合は、Enum.TryParseを使います。
C#public enum OrderStatus
{
Unknown = 0,
Pending = 1,
Processing = 2,
Completed = 3,
Canceled = 4
}
public static OrderStatus ConvertToOrderStatus(string input)
{
if (Enum.TryParse<OrderStatus>(input, ignoreCase: true, out OrderStatus status)
&& Enum.IsDefined<OrderStatus>(status))
{
return status;
}
return OrderStatus.Unknown;
}
使い方は次のとおりです。
C#OrderStatus status1 = ConvertToOrderStatus("Completed");
OrderStatus status2 = ConvertToOrderStatus("completed");
OrderStatus status3 = ConvertToOrderStatus("invalid");
Console.WriteLine(status1); // Completed
Console.WriteLine(status2); // Completed
Console.WriteLine(status3); // Unknown
TryParseだけでなく、Enum.IsDefinedも使うことで、想定外の値を防ぎやすくなります。
11-4. enumを画面表示用の選択肢に変換するサンプル
enumから画面表示用の選択肢を生成するサンプルです。
C#public enum OrderStatus
{
Unknown = 0,
Pending = 1,
Processing = 2,
Completed = 3,
Canceled = 4
}
public class SelectOption
{
public int Value { get; set; }
public string Text { get; set; } = "";
}
表示名を取得するメソッドを用意します。
C#public static string ToDisplayName(OrderStatus status)
{
return status switch
{
OrderStatus.Unknown => "不明",
OrderStatus.Pending => "受付中",
OrderStatus.Processing => "処理中",
OrderStatus.Completed => "完了",
OrderStatus.Canceled => "キャンセル",
_ => "不明"
};
}
選択肢を生成します。
C#List<SelectOption> options = Enum.GetValues<OrderStatus>()
.Select(status => new SelectOption
{
Value = (int)status,
Text = ToDisplayName(status)
})
.ToList();
foreach (SelectOption option in options)
{
Console.WriteLine($"{option.Value}: {option.Text}");
}
出力例は次のようになります。
C#0: 不明
1: 受付中
2: 処理中
3: 完了
4: キャンセル
Web画面のドロップダウンや設定画面の選択肢生成に応用できます。
11-5. enumを使った読みやすい条件分岐のサンプル
enumを使うと、条件分岐が読みやすくなります。
C#public enum PaymentType
{
Cash,
CreditCard,
BankTransfer,
ElectronicMoney
}
public static decimal CalculateFee(PaymentType paymentType, decimal amount)
{
return paymentType switch
{
PaymentType.Cash => 0,
PaymentType.CreditCard => amount * 0.03m,
PaymentType.BankTransfer => 200,
PaymentType.ElectronicMoney => amount * 0.01m,
_ => throw new ArgumentOutOfRangeException(nameof(paymentType))
};
}
使い方は次のとおりです。
C#decimal amount = 10000;
PaymentType paymentType = PaymentType.CreditCard;
decimal fee = CalculateFee(paymentType, amount);
Console.WriteLine($"手数料: {fee}");
数値や文字列で分岐するよりも、どの支払い方法に対する処理なのかが明確になります。
12. C# enumに関するよくある質問
12-1. C#のenumは内部的に何型ですか?
C#のenumは、デフォルトではint型を基にしています。
C#public enum OrderStatus
{
Pending,
Processing,
Completed
}
この場合、内部的には次のような数値が割り当てられます。
C#Pending = 0
Processing = 1
Completed = 2
基になる型は変更できます。
C#public enum Level : byte
{
Low = 1,
Medium = 2,
High = 3
}
ただし、使えるのは整数型です。stringを基にすることはできません。
12-2. enumの初期値は何になりますか?
enumの初期値は0です。
C#OrderStatus status = default;
Console.WriteLine((int)status); // 0
そのため、0に対応するメンバーを定義しておくのがおすすめです。
C#public enum OrderStatus
{
Unknown = 0,
Pending = 1,
Processing = 2,
Completed = 3
}
0を定義していない場合、初期値がどのメンバーにも対応しない状態になることがあります。
C#public enum OrderStatus
{
Pending = 1,
Processing = 2,
Completed = 3
}
OrderStatus status = default;
Console.WriteLine(status); // 0
初心者は特に、Unknown = 0やNone = 0を用意する習慣をつけると安全です。
12-3. enumに文字列の値を持たせることはできますか?
C#のenumに文字列の値を直接持たせることはできません。
次のような定義はできません。
C#public enum OrderStatus
{
Pending = "受付中" // エラー
}
enumの基になる型は整数型のみです。
日本語表示名や画面表示用の文字列が必要な場合は、switch式や属性、Dictionaryなどを使います。
C#public static string ToDisplayName(OrderStatus status)
{
return status switch
{
OrderStatus.Pending => "受付中",
OrderStatus.Processing => "処理中",
OrderStatus.Completed => "完了",
_ => "不明"
};
}
このように、enumそのものは固定選択肢として使い、表示用の文字列は別で管理するのが基本です。
12-4. enumとconstの違いは何ですか?
enumは、関連する複数の定数を1つの型としてまとめる仕組みです。
C#public enum OrderStatus
{
Pending,
Processing,
Completed
}
一方、constは単一の定数を定義するために使います。
C#public const int Pending = 0;
public const int Processing = 1;
public const int Completed = 2;
enumを使うと、変数の型として意味を持たせることができます。
C#OrderStatus status = OrderStatus.Pending;
const intの場合は、ただの数値なので、別の意味を持つ数値も代入できてしまいます。
C#int status = 999;
関連する固定選択肢を扱う場合は、constよりもenumのほうが適しています。
12-5. enumとFlagsはどう使い分ければよいですか?
通常のenumは、1つの値だけを選ぶ場合に使います。
C#public enum OrderStatus
{
Pending,
Processing,
Completed,
Canceled
}
注文状態は基本的に1つだけなので、通常のenumが向いています。
Flagsは、複数の値を同時に持つ場合に使います。
C#[Flags]
public enum Permissions
{
None = 0,
Read = 1,
Write = 2,
Delete = 4
}
ユーザー権限のように、「読み取り」と「書き込み」を同時に持てる場合はFlagsが向いています。
判断基準は、「複数の値が同時に成立するかどうか」です。
同時に成立しないなら通常のenum、同時に成立するならFlags enumを検討します。
12-6. enumを初心者が使うときに最も注意すべき点は何ですか?
初心者が最も注意すべき点は、enumには定義されていない数値も入る可能性があることです。
C#OrderStatus status = (OrderStatus)999;
このコードはコンパイルエラーになりません。
そのため、外部から受け取った数値をenumに変換する場合は、必ず有効な値か確認することが大切です。
C#int value = 999;
if (Enum.IsDefined(typeof(OrderStatus), value))
{
OrderStatus status = (OrderStatus)value;
Console.WriteLine(status);
}
else
{
Console.WriteLine("無効な値です");
}
また、0の扱いにも注意が必要です。enumの初期値は0なので、UnknownやNoneを定義しておくと安全です。
C#public enum OrderStatus
{
Unknown = 0,
Pending = 1,
Processing = 2,
Completed = 3
}
まとめ
C#のenumは、決まった選択肢を名前付きで扱うための便利な型です。
数値や文字列だけで状態や種類を管理すると、意味が分かりにくくなったり、入力ミスが発生したりすることがあります。enumを使うことで、コードの可読性が高まり、保守しやすくなります。
基本的な使い方としては、まずenumを定義し、変数やプロパティ、メソッドの引数、戻り値として利用します。
C#public enum OrderStatus
{
Unknown = 0,
Pending = 1,
Processing = 2,
Completed = 3,
Canceled = 4
}
C#OrderStatus status = OrderStatus.Completed;
if文やswitch文で分岐すると、処理の意味が分かりやすくなります。
C#if (status == OrderStatus.Completed)
{
Console.WriteLine("完了しています");
}
また、enumは数値や文字列との変換もできます。ただし、存在しない数値でもenumにキャストできてしまう点には注意が必要です。外部入力を扱う場合は、Enum.IsDefinedやEnum.TryParseを使って安全に変換しましょう。
複数の値を組み合わせたい場合は、Flags属性を使います。
C#[Flags]
public enum Permissions
{
None = 0,
Read = 1,
Write = 2,
Delete = 4
}
Flags enumでは、値を1, 2, 4, 8のように2の累乗で定義することが重要です。
実践では、enumにするべきデータと、データベースやクラスで管理すべきデータを見極めることも大切です。固定された選択肢にはenumが向いていますが、頻繁に変わるデータや付加情報が多いデータには、別の設計を検討しましょう。
C#のenumは初心者にも扱いやすく、実務でも頻繁に使われる重要な機能です。状態、種類、権限、区分などを扱う場面では、まずenumを使えないか考えてみると、読みやすく安全なコードを書きやすくなります。

