C#のenumをintに変換・取得する方法|キャストから値の比較までわかりやすく解説
はじめに
C#でenumを使っていると、「enumの値をintで取得したい」「DBに保存されているint値をenumに戻したい」「enumとintを比較したい」といった場面がよくあります。
enumは名前付きの定数を扱える便利な仕組みですが、内部的には数値で管理されています。そのため、enumとintの関係を理解しておくと、ステータス管理、区分値、APIレスポンス、DB保存値などをより安全で読みやすく扱えるようになります。
この記事では、C#のenumをintに変換・取得する方法を中心に、キャスト、Convert.ToInt32、Enum.IsDefined、Enum.Parse、Flags属性、比較方法、実践的な使い方までわかりやすく解説します。
1. C#のenumとintの基本を理解する
1-1. enumとは何か
enumは、関連する定数に名前を付けて管理するための型です。
たとえば、注文ステータスを数値だけで管理すると、次のようになります。
C#int status = 1;
この場合、1が何を意味するのかコードを見ただけではわかりにくくなります。
そこでenumを使うと、次のように意味のある名前で表現できます。
C#enum OrderStatus
{
Pending,
Processing,
Completed,
Canceled
}
使用するときは次のように書けます。
C#OrderStatus status = OrderStatus.Completed;
OrderStatus.Completedと書くことで、「注文が完了した状態」であることがコードから読み取りやすくなります。
1-2. enumの値は内部的に整数で管理される
enumは名前で扱えますが、内部的には整数値を持っています。
次の例を見てみましょう。
C#enum OrderStatus
{
Pending,
Processing,
Completed,
Canceled
}
明示的に数値を指定していない場合、最初のメンバーには0、次に1、その次に2というように自動で値が割り当てられます。
つまり、上記のenumは内部的には次のような値になります。
C#Pending = 0
Processing = 1
Completed = 2
Canceled = 3
そのため、OrderStatus.Completedをintに変換すると2になります。
1-3. enumの既定の基になる型はint
C#のenumは、既定ではintを基になる型として使用します。
次の定義は、内部的にはint型の値を持つenumです。
C#enum UserRole
{
Guest,
Member,
Admin
}
これは次のように書いた場合とほぼ同じ意味になります。
C#enum UserRole : int
{
Guest,
Member,
Admin
}
通常は: intを省略して問題ありません。C#のenumは、何も指定しなければintとして扱われるためです。
1-4. enumメンバーに明示的な数値を割り当てる方法
enumの各メンバーには、明示的に数値を割り当てることもできます。
C#enum HttpStatus
{
OK = 200,
BadRequest = 400,
Unauthorized = 401,
NotFound = 404,
InternalServerError = 500
}
このように定義すると、HTTPステータスコードのような既に意味が決まっている数値を、読みやすい名前で扱えます。
C#HttpStatus status = HttpStatus.NotFound;
int code = (int)status;
Console.WriteLine(code);
実行結果は次のようになります。
C#404
明示的な数値を割り当てることで、外部システムやDB、APIで使われる数値とenumを対応させやすくなります。
1-5. enumをintとして扱う場面
enumをintとして扱う場面は多くあります。
代表的な例は次のようなケースです。
C#enum PaymentStatus
{
Unpaid = 0,
Paid = 1,
Refunded = 2
}
たとえば、DBにPaymentStatusを保存するとき、enumの名前ではなく数値として保存する設計があります。
C#PaymentStatus status = PaymentStatus.Paid;
int dbValue = (int)status;
この場合、PaymentStatus.Paidは1として保存できます。
また、APIから次のような数値が返ってくることもあります。
C#int responseStatus = 2;
この数値をenumに変換すれば、コード上では意味のある名前で扱えます。
C#PaymentStatus status = (PaymentStatus)responseStatus;
このように、enumとintの変換は、DB、API、ログ、設定値、画面の選択肢などでよく使われます。
2. enumをintに変換して値を取得する方法
2-1. キャストでenumをintに変換する
C#でenumをintに変換する基本的な方法は、明示的キャストです。
C#enum UserRole
{
Guest = 0,
Member = 1,
Admin = 2
}
UserRole.Adminをintに変換するには、次のように書きます。
C#UserRole role = UserRole.Admin;
int value = (int)role;
Console.WriteLine(value);
実行結果は次のとおりです。
C#2
enumは内部的に数値を持っていますが、intへは暗黙的に変換されません。そのため、(int)を使って明示的に変換する必要があります。
2-2. enum変数からint値を取得する
enum変数に入っている値からint値を取得する場合も、同じようにキャストします。
C#enum TaskStatus
{
Todo = 0,
Doing = 1,
Done = 2
}
TaskStatus status = TaskStatus.Doing;
int statusValue = (int)status;
Console.WriteLine(statusValue);
実行結果は次のようになります。
C#1
TaskStatus.Doingには1が割り当てられているため、intに変換すると1が取得できます。
メソッドの戻り値としてintを返したい場合も、次のように書けます。
C#static int GetStatusValue(TaskStatus status)
{
return (int)status;
}
使用例は次のとおりです。
C#int value = GetStatusValue(TaskStatus.Done);
Console.WriteLine(value);
実行結果は次のようになります。
C#2
2-3. Console.WriteLineでenum名とint値の違いを確認する
enumをそのままConsole.WriteLineに渡すと、数値ではなく名前が表示されます。
C#enum ColorType
{
Red = 1,
Green = 2,
Blue = 3
}
ColorType color = ColorType.Green;
Console.WriteLine(color);
Console.WriteLine((int)color);
実行結果は次のようになります。
C#Green
2
Console.WriteLine(color)ではenumの名前であるGreenが表示されます。
一方、Console.WriteLine((int)color)では、内部的な数値である2が表示されます。
つまり、enum名を表示したい場合はそのまま出力し、数値を表示したい場合はintにキャストします。
2-4. Convert.ToInt32を使ってintに変換する
enumをintに変換する方法として、Convert.ToInt32を使うこともできます。
C#enum Priority
{
Low = 1,
Middle = 2,
High = 3
}
Priority priority = Priority.High;
int value = Convert.ToInt32(priority);
Console.WriteLine(value);
実行結果は次のとおりです。
C#3
Convert.ToInt32を使うと、enum値をintに変換できます。
ただし、単純にenumをintへ変換するだけであれば、通常はキャストの方が簡潔です。
C#int value = (int)priority;
2-5. キャストとConvert.ToInt32の使い分け
enumをintに変換する場合、基本的には明示的キャストを使うのが一般的です。
C#int value = (int)priority;
コードが短く、enumを数値に変換していることが明確だからです。
一方、Convert.ToInt32は、値を汎用的に変換したい場合や、objectとして扱っている値を変換する場合に使われることがあります。
C#object value = Priority.High;
int intValue = Convert.ToInt32(value);
ただし、enumの基になる型がlongなどで、intの範囲を超える値を持っている場合、Convert.ToInt32では例外が発生する可能性があります。
通常のenumは既定でintなので、基本は次の書き方で問題ありません。
C#int value = (int)priority;
3. intをenumに変換する方法
3-1. キャストでintをenumに変換する
intをenumに変換する場合も、明示的キャストを使います。
C#enum OrderStatus
{
Pending = 0,
Processing = 1,
Completed = 2,
Canceled = 3
}
int value = 2;
OrderStatus status = (OrderStatus)value;
Console.WriteLine(status);
実行結果は次のようになります。
C#Completed
2はOrderStatus.Completedに対応しているため、enumに変換するとCompletedとして扱えます。
3-2. Enum.ToObjectを使ってintからenumを生成する
Enum.ToObjectを使って、数値からenumを生成することもできます。
C#int value = 1;
OrderStatus status = (OrderStatus)Enum.ToObject(typeof(OrderStatus), value);
Console.WriteLine(status);
実行結果は次のとおりです。
C#Processing
Enum.ToObjectは、型を実行時に指定してenumへ変換したい場合に使われます。
ただし、通常のコードではキャストの方が簡潔です。
C#OrderStatus status = (OrderStatus)value;
Enum.ToObjectは、リフレクションを使った処理や、Typeを動的に扱う処理で役立ちます。
3-3. 存在しない数値をenumに変換できてしまう点に注意
intからenumへの変換では、定義されていない数値でも変換できてしまいます。
C#enum OrderStatus
{
Pending = 0,
Processing = 1,
Completed = 2,
Canceled = 3
}
int value = 99;
OrderStatus status = (OrderStatus)value;
Console.WriteLine(status);
実行結果は次のようになります。
C#99
OrderStatusには99という値は定義されていません。
しかし、C#ではintをenumにキャストできるため、未定義の値でもenum変数に入れることができます。
これはDBやAPIなど、外部から数値を受け取る場合に特に注意が必要です。
3-4. Enum.IsDefinedで有効な値か確認する
int値がenumに定義されているか確認するには、Enum.IsDefinedを使います。
C#int value = 2;
bool isDefined = Enum.IsDefined(typeof(OrderStatus), value);
Console.WriteLine(isDefined);
実行結果は次のようになります。
C#True
未定義の値を確認すると、次のようになります。
C#int value = 99;
bool isDefined = Enum.IsDefined(typeof(OrderStatus), value);
Console.WriteLine(isDefined);
実行結果は次のとおりです。
C#False
Enum.IsDefinedで確認してから変換すると、意図しない値がenumに入るのを防げます。
C#int value = 2;
if (Enum.IsDefined(typeof(OrderStatus), value))
{
OrderStatus status = (OrderStatus)value;
Console.WriteLine(status);
}
else
{
Console.WriteLine("無効なステータスです。");
}
3-5. 入力値やDBの値をenumに変換する実装例
DBに保存されたint値をenumに変換する例を見てみましょう。
C#enum UserStatus
{
Unknown = 0,
Active = 1,
Suspended = 2,
Deleted = 3
}
int dbValue = 1;
UserStatus status;
if (Enum.IsDefined(typeof(UserStatus), dbValue))
{
status = (UserStatus)dbValue;
}
else
{
status = UserStatus.Unknown;
}
Console.WriteLine(status);
実行結果は次のようになります。
C#Active
外部から取得した値は、必ず想定どおりとは限りません。
そのため、DB、API、画面入力などから取得したint値をenumに変換するときは、次のような流れにすると安全です。
C#int inputValue = 5;
if (!Enum.IsDefined(typeof(UserStatus), inputValue))
{
Console.WriteLine("定義されていない値です。");
return;
}
UserStatus status = (UserStatus)inputValue;
外部入力を扱う場合は、単純にキャストするだけでなく、値の検証を組み合わせることが大切です。
4. enumとintを比較する方法
4-1. enum同士を比較する
enum同士は、そのまま比較できます。
C#enum UserRole
{
Guest = 0,
Member = 1,
Admin = 2
}
UserRole role = UserRole.Admin;
if (role == UserRole.Admin)
{
Console.WriteLine("管理者です。");
}
このように、同じenum型同士であれば、==で比較できます。
enumを使うメリットは、数値ではなく意味のある名前で比較できることです。
C#if (role == UserRole.Admin)
{
Console.WriteLine("管理者画面を表示します。");
}
次のように数値で比較するよりも、コードの意味がわかりやすくなります。
C#if ((int)role == 2)
{
Console.WriteLine("管理者画面を表示します。");
}
4-2. enumをintに変換して比較する
enumとintを比較したい場合は、enumをintに変換してから比較します。
C#UserRole role = UserRole.Admin;
int adminValue = 2;
if ((int)role == adminValue)
{
Console.WriteLine("Adminと一致しました。");
}
roleを(int)roleとして変換することで、int値と比較できます。
ただし、コードの可読性を考えると、可能であればenum同士で比較する方が望ましいです。
C#if (role == UserRole.Admin)
{
Console.WriteLine("Adminと一致しました。");
}
intとの比較が必要になるのは、DBやAPIなど外部から数値として値を受け取る場合が多いです。
4-3. intをenumに変換して比較する
intをenumに変換してから比較する方法もあります。
C#int value = 2;
UserRole role = (UserRole)value;
if (role == UserRole.Admin)
{
Console.WriteLine("管理者です。");
}
この方法では、比較対象がenumになるため、意味のある名前で比較できます。
ただし、intからenumに変換する場合は、未定義の値が入る可能性があります。
そのため、外部から取得した値を変換する場合は、事前にEnum.IsDefinedで確認すると安全です。
C#int value = 2;
if (Enum.IsDefined(typeof(UserRole), value))
{
UserRole role = (UserRole)value;
if (role == UserRole.Admin)
{
Console.WriteLine("管理者です。");
}
}
else
{
Console.WriteLine("無効なロールです。");
}
4-4. 比較時に型が一致しない場合のエラー
enumとintをそのまま比較しようとすると、型が一致しないためエラーになります。
C#UserRole role = UserRole.Admin;
if (role == 2)
{
Console.WriteLine("管理者です。");
}
このような比較は避け、次のいずれかの方法を使います。
C#if ((int)role == 2)
{
Console.WriteLine("管理者です。");
}
または、intをenumに変換します。
C#if (role == (UserRole)2)
{
Console.WriteLine("管理者です。");
}
ただし、最も読みやすいのは次の書き方です。
C#if (role == UserRole.Admin)
{
Console.WriteLine("管理者です。");
}
4-5. 安全に比較するための考え方
enumとintを安全に比較するには、できるだけenum同士で比較することが重要です。
よくない例は次のようなコードです。
C#if ((int)status == 1)
{
Console.WriteLine("処理中です。");
}
このコードでは、1が何を意味しているのかすぐにわかりません。
よりよい書き方は次のとおりです。
C#if (status == OrderStatus.Processing)
{
Console.WriteLine("処理中です。");
}
どうしてもint値と比較する必要がある場合は、変換の意図がわかるように書きます。
C#int dbStatus = 1;
if (Enum.IsDefined(typeof(OrderStatus), dbStatus))
{
OrderStatus status = (OrderStatus)dbStatus;
if (status == OrderStatus.Processing)
{
Console.WriteLine("処理中です。");
}
}
数値を直接比較しすぎると、enumを使うメリットが薄れてしまいます。基本的には、変換は境界部分で行い、アプリケーション内部ではenumとして扱うのがおすすめです。
5. enumの基になる型を変更する方法
5-1. enumの基になる型とは
enumには、内部的な数値を保持するための型があります。
これを「基になる型」と呼びます。
通常、C#のenumの基になる型はintです。
C#enum SampleStatus
{
None = 0,
Active = 1,
Inactive = 2
}
上記は次のように書いた場合と同じように扱われます。
C#enum SampleStatus : int
{
None = 0,
Active = 1,
Inactive = 2
}
5-2. byte・short・longなどを指定する書き方
enumの基になる型は、int以外にも変更できます。
指定できる主な型は次のような整数型です。
C#byte
sbyte
short
ushort
int
uint
long
ulong
たとえば、byteを基になる型にする場合は次のように書きます。
C#enum SmallStatus : byte
{
None = 0,
Active = 1,
Inactive = 2
}
longを使う場合は次のようになります。
C#enum LargeStatus : long
{
None = 0,
First = 10000000000L,
Second = 20000000000L
}
大量の値を扱う場合や、外部仕様で数値の型が決まっている場合は、基になる型を明示することがあります。
5-3. int以外のenumを数値に変換する方法
基になる型がbyteの場合は、byteにキャストできます。
C#enum SmallStatus : byte
{
None = 0,
Active = 1,
Inactive = 2
}
SmallStatus status = SmallStatus.Active;
byte value = (byte)status;
Console.WriteLine(value);
実行結果は次のとおりです。
C#1
基になる型がlongの場合は、longにキャストします。
C#enum LargeStatus : long
{
None = 0,
First = 10000000000L,
Second = 20000000000L
}
LargeStatus status = LargeStatus.First;
long value = (long)status;
Console.WriteLine(value);
このように、enumの基になる型に合わせてキャストすることで、正しい数値を取得できます。
int以外の基になる型を使っているenumを無理にintへ変換すると、値の範囲によっては問題が起きる可能性があります。
5-4. Enum.GetUnderlyingTypeで基になる型を取得する
Enum.GetUnderlyingTypeを使うと、enumの基になる型を取得できます。
C#Type type = Enum.GetUnderlyingType(typeof(SmallStatus));
Console.WriteLine(type);
実行結果は次のようになります。
C#System.Byte
intを基になる型にしている場合は、次のようになります。
C#enum NormalStatus
{
None = 0,
Active = 1
}
Type type = Enum.GetUnderlyingType(typeof(NormalStatus));
Console.WriteLine(type);
実行結果は次のとおりです。
C#System.Int32
ライブラリや共通処理で、enumの型を動的に扱う場合に便利です。
5-5. 基になる型を変更する際の注意点
enumの基になる型は、特別な理由がなければ既定のintのままで問題ありません。
むやみにbyteやlongに変更すると、変換処理や外部システムとの連携で意図しない混乱が起きることがあります。
たとえば、DBのカラムがintなのに、C#側のenumをbyteにすると、型の違いを意識する必要があります。
C#enum UserStatus : byte
{
None = 0,
Active = 1,
Suspended = 2
}
この場合、DBから取得したint値をそのまま扱うのではなく、範囲や型を考慮する必要があります。
基本方針としては、次のように考えるとよいでしょう。
通常の用途では、既定のintを使います。
C#enum UserStatus
{
None = 0,
Active = 1,
Suspended = 2
}
外部仕様やメモリ効率など、明確な理由がある場合だけ基になる型を変更します。
C#enum UserStatus : byte
{
None = 0,
Active = 1,
Suspended = 2
}
6. enumの名前・文字列・数値を相互に扱う方法
6-1. enumから名前を取得する
enumの名前を取得したい場合は、ToStringを使います。
C#enum UserRole
{
Guest = 0,
Member = 1,
Admin = 2
}
UserRole role = UserRole.Admin;
string name = role.ToString();
Console.WriteLine(name);
実行結果は次のようになります。
C#Admin
ToStringを使うと、enumのメンバー名を文字列として取得できます。
画面表示、ログ出力、デバッグなどでよく使われます。
6-2. enumから数値を取得する
enumから数値を取得するには、intにキャストします。
C#UserRole role = UserRole.Admin;
int value = (int)role;
Console.WriteLine(value);
実行結果は次のとおりです。
C#2
名前と数値の両方を表示したい場合は、次のように書けます。
C#Console.WriteLine($"{role} = {(int)role}");
実行結果は次のようになります。
C#Admin = 2
6-3. 文字列からenumに変換する
文字列からenumに変換するには、Enum.ParseまたはEnum.TryParseを使います。
C#string text = "Admin";
UserRole role = (UserRole)Enum.Parse(typeof(UserRole), text);
Console.WriteLine(role);
実行結果は次のとおりです。
C#Admin
ジェネリック版を使うと、より簡潔に書けます。
C#string text = "Admin";
UserRole role = Enum.Parse<UserRole>(text);
Console.WriteLine(role);
ただし、存在しない文字列を渡すと例外が発生します。
C#string text = "Owner";
UserRole role = Enum.Parse<UserRole>(text);
このような可能性がある場合は、Enum.TryParseを使う方が安全です。
6-4. Enum.ParseとEnum.TryParseの違い
Enum.Parseは、変換に失敗すると例外を発生させます。
C#string text = "Admin";
UserRole role = Enum.Parse<UserRole>(text);
一方、Enum.TryParseは、変換に成功したかどうかをboolで返します。
C#string text = "Admin";
if (Enum.TryParse<UserRole>(text, out UserRole role))
{
Console.WriteLine(role);
}
else
{
Console.WriteLine("変換できませんでした。");
}
ユーザー入力や外部データを扱う場合は、TryParseを使う方が安全です。
大文字小文字を無視して変換したい場合は、次のように書けます。
C#string text = "admin";
if (Enum.TryParse<UserRole>(text, ignoreCase: true, out UserRole role))
{
Console.WriteLine(role);
}
実行結果は次のとおりです。
C#Admin
ただし、TryParseは数値文字列を変換できる場合があります。
C#string text = "99";
if (Enum.TryParse<UserRole>(text, out UserRole role))
{
Console.WriteLine(role);
}
この場合、99がUserRoleに定義されていなくても変換が成功することがあります。
そのため、厳密に定義済みの値だけを許可したい場合は、Enum.IsDefinedも組み合わせます。
C#string text = "99";
if (Enum.TryParse<UserRole>(text, out UserRole role) &&
Enum.IsDefined(typeof(UserRole), role))
{
Console.WriteLine(role);
}
else
{
Console.WriteLine("無効な値です。");
}
6-5. 数値・文字列・enumを組み合わせた実用例
たとえば、APIからステータスが数値で返ってくるケースを考えます。
C#enum ApiStatus
{
Unknown = 0,
Success = 1,
Error = 2
}
APIレスポンスとして、次のようなint値を受け取ったとします。
C#int responseCode = 1;
この値をenumに変換し、名前と数値をログに出力します。
C#ApiStatus status;
if (Enum.IsDefined(typeof(ApiStatus), responseCode))
{
status = (ApiStatus)responseCode;
}
else
{
status = ApiStatus.Unknown;
}
Console.WriteLine($"StatusName: {status}");
Console.WriteLine($"StatusValue: {(int)status}");
実行結果は次のようになります。
C#StatusName: Success
StatusValue: 1
このように、外部ではint、内部ではenum、表示やログでは文字列という形で使い分けると、コードの安全性と可読性を両立できます。
7. Flags属性を使うenumとintの扱い
7-1. Flags属性とは
Flags属性は、enumをビットフラグとして扱うために使います。
通常のenumは、ひとつの値を表します。
C#enum UserRole
{
Guest = 0,
Member = 1,
Admin = 2
}
一方、Flags属性を使うと、複数の値を組み合わせて表現できます。
C#[Flags]
enum Permission
{
None = 0,
Read = 1,
Write = 2,
Execute = 4
}
権限管理のように、「読み取り可能」「書き込み可能」「実行可能」を組み合わせたい場合に便利です。
7-2. ビットフラグとしてenumを定義する方法
Flags属性を使う場合、それぞれの値は1, 2, 4, 8, 16のように2の累乗で定義します。
C#[Flags]
enum Permission
{
None = 0,
Read = 1,
Write = 2,
Execute = 4,
Delete = 8
}
2の累乗にすることで、それぞれのフラグをビット単位で区別できます。
次のように定義してしまうと、組み合わせの判定がわかりにくくなります。
C#[Flags]
enum BadPermission
{
None = 0,
Read = 1,
Write = 2,
Execute = 3
}
Execute = 3は、ビット的にはReadとWriteを組み合わせた値と同じになってしまいます。
そのため、Flags属性を使う場合は、基本的に2の累乗で値を定義します。
7-3. 複数のenum値を組み合わせる方法
複数のenum値を組み合わせるには、ビットOR演算子の|を使います。
C#Permission permission = Permission.Read | Permission.Write;
Console.WriteLine(permission);
Console.WriteLine((int)permission);
実行結果は次のようになります。
C#Read, Write
3
Readは1、Writeは2です。
これらを組み合わせると、数値としては3になります。
C#1 | 2 = 3
さらにExecuteも組み合わせると、次のようになります。
C#Permission permission = Permission.Read | Permission.Write | Permission.Execute;
Console.WriteLine(permission);
Console.WriteLine((int)permission);
実行結果は次のとおりです。
C#Read, Write, Execute
7
Read = 1、Write = 2、Execute = 4なので、合計すると7になります。
7-4. int値としてフラグの状態を確認する方法
Flags付きのenumも、intに変換できます。
C#Permission permission = Permission.Read | Permission.Write;
int value = (int)permission;
Console.WriteLine(value);
実行結果は次のようになります。
C#3
DBに権限を数値として保存したい場合などに利用できます。
逆に、DBから取得したint値をenumに戻すこともできます。
C#int dbValue = 3;
Permission permission = (Permission)dbValue;
Console.WriteLine(permission);
実行結果は次のとおりです。
C#Read, Write
フラグが含まれているかを確認するには、ビットAND演算子の&を使えます。
C#Permission permission = Permission.Read | Permission.Write;
bool canRead = (permission & Permission.Read) == Permission.Read;
Console.WriteLine(canRead);
実行結果は次のようになります。
C#True
7-5. HasFlagを使った判定方法
HasFlagを使うと、指定したフラグが含まれているかを簡潔に判定できます。
C#Permission permission = Permission.Read | Permission.Write;
if (permission.HasFlag(Permission.Read))
{
Console.WriteLine("読み取り権限があります。");
}
if (permission.HasFlag(Permission.Execute))
{
Console.WriteLine("実行権限があります。");
}
実行結果は次のようになります。
C#読み取り権限があります。
HasFlagは読みやすいコードを書ける便利なメソッドです。
ただし、None = 0に対してHasFlagを使う場合は注意が必要です。0はどのビットも立っていない状態なので、判定の意図を明確にする必要があります。
Noneかどうかを確認する場合は、次のように直接比較する方がわかりやすいです。
C#if (permission == Permission.None)
{
Console.WriteLine("権限がありません。");
}
8. enumとint変換でよくあるエラー・注意点
8-1. enumはintへ暗黙的に変換できない
enumは内部的には整数ですが、intへ暗黙的には変換できません。
次のコードはエラーになります。
C#UserRole role = UserRole.Admin;
int value = role;
正しくは、明示的にキャストします。
C#int value = (int)role;
C#では型安全性を保つため、enumとintを自動的には変換しません。
そのため、enumから数値を取得したい場合は、必ず明示的に変換しましょう。
8-2. intからenumへの変換で未定義値が入る
intからenumへはキャストできますが、未定義の値でも入ってしまいます。
C#UserRole role = (UserRole)999;
Console.WriteLine(role);
実行結果は次のようになります。
C#999
これは、UserRoleに999が定義されていなくても、数値として保持できてしまうためです。
外部から取得した値を扱う場合は、必ず検証しましょう。
C#int value = 999;
if (Enum.IsDefined(typeof(UserRole), value))
{
UserRole role = (UserRole)value;
}
else
{
Console.WriteLine("未定義の値です。");
}
8-3. enumの値が重複している場合の注意
C#のenumでは、複数のメンバーに同じ数値を割り当てることができます。
C#enum ResultCode
{
Success = 0,
OK = 0,
Error = 1
}
このような定義は文法上は可能です。
ただし、同じ値に複数の名前があると、表示や変換のときに混乱しやすくなります。
C#ResultCode code = ResultCode.Success;
Console.WriteLine(code);
Console.WriteLine((int)code);
値が重複していると、「どの名前を代表として扱うのか」がわかりにくくなることがあります。
特別な理由がない限り、enumの値は重複させない方が安全です。
8-4. 0の値を定義しておくべき理由
enumでは、0の値を定義しておくことをおすすめします。
C#enum UserStatus
{
Unknown = 0,
Active = 1,
Suspended = 2,
Deleted = 3
}
理由は、enumの既定値が0だからです。
C#UserStatus status = default;
Console.WriteLine(status);
0に対応するメンバーが定義されていないと、意図しない状態になる可能性があります。
たとえば、次のような定義では注意が必要です。
C#enum UserStatus
{
Active = 1,
Suspended = 2,
Deleted = 3
}
この場合、default(UserStatus)は0ですが、0に対応する名前がありません。
そのため、UnknownやNoneのような名前で0を定義しておくと安全です。
C#enum UserStatus
{
Unknown = 0,
Active = 1,
Suspended = 2,
Deleted = 3
}
8-5. マジックナンバーを避ける設計のポイント
enumを使う大きな目的は、マジックナンバーを避けることです。
マジックナンバーとは、意味がわかりにくい数値を直接コードに書くことです。
C#if (status == 2)
{
Console.WriteLine("完了です。");
}
このコードでは、2が何を意味するのかわかりにくいです。
enumを使うと、次のように書けます。
C#if (status == OrderStatus.Completed)
{
Console.WriteLine("完了です。");
}
こちらの方が、コードの意図が明確です。
数値が必要な場面ではintに変換してもよいですが、アプリケーション内部ではなるべくenumの名前で扱うようにしましょう。
C#int dbValue = (int)OrderStatus.Completed;
DBやAPIとの境界ではintに変換し、ビジネスロジックではenumとして扱うのが基本です。
9. enumとint変換の実践サンプル
9-1. ステータスコードをenumで管理する例
注文ステータスをenumで管理する例を見てみましょう。
C#enum OrderStatus
{
Unknown = 0,
New = 1,
Paid = 2,
Shipped = 3,
Completed = 4,
Canceled = 5
}
注文が完了しているか判定する処理は、次のように書けます。
C#OrderStatus status = OrderStatus.Completed;
if (status == OrderStatus.Completed)
{
Console.WriteLine("注文は完了しています。");
}
数値で書くよりも意味がわかりやすくなります。
C#if ((int)status == 4)
{
Console.WriteLine("注文は完了しています。");
}
この書き方でも動作しますが、4の意味がわかりにくいため、基本的にはenum名で比較する方がよいです。
9-2. DBに保存されたint値をenumに変換する例
DBに注文ステータスがintとして保存されているケースを考えます。
C#int dbStatus = 2;
この値をOrderStatusに変換します。
C#OrderStatus status;
if (Enum.IsDefined(typeof(OrderStatus), dbStatus))
{
status = (OrderStatus)dbStatus;
}
else
{
status = OrderStatus.Unknown;
}
Console.WriteLine(status);
実行結果は次のようになります。
C#Paid
未定義の値がDBに入っている可能性を考慮して、Enum.IsDefinedでチェックしてから変換しています。
より実用的にメソッド化すると、次のように書けます。
C#static OrderStatus ToOrderStatus(int value)
{
if (Enum.IsDefined(typeof(OrderStatus), value))
{
return (OrderStatus)value;
}
return OrderStatus.Unknown;
}
使用例は次のとおりです。
C#int dbStatus = 3;
OrderStatus status = ToOrderStatus(dbStatus);
Console.WriteLine(status);
実行結果は次のようになります。
C#Shipped
9-3. APIレスポンスの数値をenumに変換する例
APIから数値のステータスが返ってくる場合も、enumに変換すると扱いやすくなります。
C#enum ApiResult
{
Unknown = 0,
Success = 1,
ValidationError = 2,
ServerError = 3
}
APIレスポンスの値が次のように取得できたとします。
C#int responseCode = 1;
この値をenumに変換します。
C#ApiResult result;
if (Enum.IsDefined(typeof(ApiResult), responseCode))
{
result = (ApiResult)responseCode;
}
else
{
result = ApiResult.Unknown;
}
if (result == ApiResult.Success)
{
Console.WriteLine("API処理は成功しました。");
}
else
{
Console.WriteLine($"API処理に失敗しました: {result}");
}
外部APIでは、仕様変更などによって想定外の数値が返ってくる可能性もあります。
そのため、未定義値をUnknownとして扱えるようにしておくと、例外や不正な分岐を防ぎやすくなります。
9-4. switch文でenumを分岐する例
enumはswitch文との相性もよいです。
C#OrderStatus status = OrderStatus.Shipped;
switch (status)
{
case OrderStatus.New:
Console.WriteLine("新規注文です。");
break;
case OrderStatus.Paid:
Console.WriteLine("支払い済みです。");
break;
case OrderStatus.Shipped:
Console.WriteLine("発送済みです。");
break;
case OrderStatus.Completed:
Console.WriteLine("完了済みです。");
break;
case OrderStatus.Canceled:
Console.WriteLine("キャンセル済みです。");
break;
default:
Console.WriteLine("不明なステータスです。");
break;
}
実行結果は次のようになります。
C#発送済みです。
intの値で分岐するよりも、enumの名前で分岐した方が読みやすくなります。
C#switch ((int)status)
{
case 1:
Console.WriteLine("新規注文です。");
break;
case 2:
Console.WriteLine("支払い済みです。");
break;
}
このような書き方では、数値の意味を毎回確認する必要があります。
enumを使えば、分岐条件そのものが意味を持つため、保守しやすいコードになります。
9-5. enumを使って可読性を高める実装例
ユーザーのアカウント状態を判定する処理を考えます。
まず、数値だけで書いた例です。
C#int userStatus = 2;
if (userStatus == 1)
{
Console.WriteLine("有効なユーザーです。");
}
else if (userStatus == 2)
{
Console.WriteLine("停止中のユーザーです。");
}
else if (userStatus == 3)
{
Console.WriteLine("削除済みのユーザーです。");
}
このコードでは、1、2、3の意味を覚えておく必要があります。
enumを使うと、次のように書けます。
C#enum UserStatus
{
Unknown = 0,
Active = 1,
Suspended = 2,
Deleted = 3
}
C#UserStatus userStatus = UserStatus.Suspended;
if (userStatus == UserStatus.Active)
{
Console.WriteLine("有効なユーザーです。");
}
else if (userStatus == UserStatus.Suspended)
{
Console.WriteLine("停止中のユーザーです。");
}
else if (userStatus == UserStatus.Deleted)
{
Console.WriteLine("削除済みのユーザーです。");
}
このように、enumを使うことでコードの意図が明確になります。
DBやAPIではintを使い、アプリケーション内部ではenumを使うようにすると、実装の読みやすさとデータ連携のしやすさを両立できます。
10. C#のenumをintに変換・取得するときのベストプラクティス
10-1. 基本は明示的キャストを使う
C#でenumをintに変換する場合、基本は明示的キャストを使います。
C#int value = (int)OrderStatus.Completed;
最もシンプルで、意図も明確です。
Convert.ToInt32も使えますが、通常のenumからintへの変換であれば、キャストの方が自然です。
C#int value = Convert.ToInt32(OrderStatus.Completed);
どちらでも変換できますが、特別な理由がなければ次の書き方で十分です。
C#int value = (int)status;
10-2. 外部入力はEnum.IsDefinedやTryParseで検証する
DB、API、画面入力など、外部から取得した値をenumに変換する場合は、必ず検証を行いましょう。
int値の場合は、Enum.IsDefinedを使います。
C#int value = 2;
if (Enum.IsDefined(typeof(OrderStatus), value))
{
OrderStatus status = (OrderStatus)value;
}
else
{
Console.WriteLine("無効な値です。");
}
文字列の場合は、Enum.TryParseを使います。
C#string text = "Completed";
if (Enum.TryParse<OrderStatus>(text, out OrderStatus status) &&
Enum.IsDefined(typeof(OrderStatus), status))
{
Console.WriteLine(status);
}
else
{
Console.WriteLine("無効なステータスです。");
}
intからenumへのキャストは未定義値も許可してしまうため、外部入力では検証を忘れないことが重要です。
10-3. int値を直接比較しすぎない
enumを使っているのに、コード内でint値を直接比較しすぎると、可読性が下がります。
避けたい例は次のようなコードです。
C#if ((int)status == 4)
{
Console.WriteLine("完了です。");
}
よりよい書き方は次のとおりです。
C#if (status == OrderStatus.Completed)
{
Console.WriteLine("完了です。");
}
enumを使う目的は、数値に意味のある名前を付けることです。
そのため、アプリケーション内部の判定では、なるべくenumの名前を使いましょう。
数値への変換は、DB保存、API送信、ログ出力など、必要な場所に限定するのがおすすめです。
C#int valueForDb = (int)status;
10-4. 用途に応じて基になる型を明示する
通常のenumでは、基になる型はintのままで問題ありません。
C#enum OrderStatus
{
Unknown = 0,
New = 1,
Paid = 2,
Completed = 3
}
ただし、外部仕様でbyteやlongが指定されている場合は、基になる型を明示するとよいでしょう。
C#enum SmallStatus : byte
{
Unknown = 0,
Active = 1,
Inactive = 2
}
C#enum LargeCode : long
{
None = 0,
First = 10000000000L
}
基になる型を変更する場合は、変換先の型にも注意します。
C#SmallStatus small = SmallStatus.Active;
byte smallValue = (byte)small;
C#LargeCode large = LargeCode.First;
long largeValue = (long)large;
int以外の基になる型を使う場合は、値の範囲、DBの型、API仕様との整合性を確認しておきましょう。
まとめ
C#のenumは、名前付きの定数を扱うための便利な型です。内部的には整数値で管理されており、既定の基になる型はintです。
enumをintに変換して値を取得するには、基本的に明示的キャストを使います。
C#int value = (int)status;
Convert.ToInt32でも変換できますが、通常はキャストの方が簡潔でわかりやすいです。
逆に、intをenumに変換する場合もキャストを使います。
C#OrderStatus status = (OrderStatus)value;
ただし、intからenumへの変換では、定義されていない数値でも入ってしまう点に注意が必要です。
外部入力、DB、APIレスポンスなどを扱う場合は、Enum.IsDefinedやEnum.TryParseを使って検証しましょう。
C#if (Enum.IsDefined(typeof(OrderStatus), value))
{
OrderStatus status = (OrderStatus)value;
}
enumとintを比較する場合は、型をそろえる必要があります。ただし、できるだけint値を直接比較するのではなく、enum同士で比較する方が安全で読みやすいです。
C#if (status == OrderStatus.Completed)
{
Console.WriteLine("完了です。");
}
また、Flags属性を使うと、複数のenum値をビットフラグとして組み合わせることもできます。
C#Permission permission = Permission.Read | Permission.Write;
int value = (int)permission;
C#でenumとintを扱うときは、次のポイントを意識するとよいでしょう。
C#// enumからintへ
int value = (int)status;
// intからenumへ
OrderStatus status = (OrderStatus)value;
// 外部入力の検証
bool isValid = Enum.IsDefined(typeof(OrderStatus), value);
enumは、数値に意味を持たせ、コードの可読性を高めるための仕組みです。数値変換が必要な場面では正しくintに変換しつつ、アプリケーション内部ではできるだけenumとして扱うことで、安全で保守しやすいC#コードを書けるようになります。

