DOBON.NET プログラミング道: .NET Framework, VB.NET, C#, Visual Basic, Visual Studio, インストーラ, ...

数値や文字列を列挙体に変換する

ここでは、数値を列挙体の値に変換する方法と、列挙体のメンバの名前や値を示す文字列を列挙体の値に変換する方法を紹介します。

数値を列挙体の値に変換する

数値を列挙体の値に変換するには、キャストをします。または、Enum.ToObjectメソッドを使います。

以下の例では、Int32型の数値をDayOfWeek列挙体の値に変換しています。

VB.NET
コードを隠すコードを選択
'変換する数値
Dim val As Integer = 1

'DayOfWeek列挙体に変換する
'キャストする
Dim dow As DayOfWeek = DirectCast(val, DayOfWeek)
'Enum.ToObjectメソッドを使うと、以下のようになる
Dim dow2 As DayOfWeek = DirectCast([Enum].ToObject(GetType(DayOfWeek), val), DayOfWeek)

'結果を表示する
Console.WriteLine(dow)
'"Monday"と表示される
C#
コードを隠すコードを選択
//変換する数値
int val = 1;

//DayOfWeek列挙体に変換する
//キャストする
DayOfWeek dow = (DayOfWeek)val;
//Enum.ToObjectメソッドを使うと、以下のようになる
DayOfWeek dow2 = (DayOfWeek)Enum.ToObject(typeof(DayOfWeek), val);

//結果を表示する
Console.WriteLine(dow);
//"Monday"と表示される

FlagsAttribute属性が適用された列挙体であっても、この方法で変換できます。以下の例では、Int32型の数値をAttributeTargets列挙体の値に変換しています。

VB.NET
コードを隠すコードを選択
'変換する数値
Dim val As Integer = 9

Dim at As AttributeTargets = DirectCast(val, AttributeTargets)
Dim at2 As AttributeTargets = _
    DirectCast([Enum].ToObject(GetType(AttributeTargets), val), AttributeTargets)

Console.WriteLine(at)
'"Assembly, Struct"と表示される
C#
コードを隠すコードを選択
//変換する数値
int val = 9;

AttributeTargets at = (AttributeTargets)val;
AttributeTargets at2 = (AttributeTargets)Enum.ToObject(typeof(AttributeTargets), val);

Console.WriteLine(at);
//"Assembly, Struct"と表示される

文字列を列挙体に変換する

列挙体のメンバ名や値を示す文字列を列挙体の値に変換するには、Enum.Parseメソッドを使います。変換できる文字列は、列挙体のメンバの名前か、列挙体を示す数値の文字列です。

以下に、文字列をDayOfWeek列挙体に変換する例を示します。

VB.NET
コードを隠すコードを選択
'変換する文字列
Dim str As String = "Monday"
'次のような数値を文字列にしたものも変換できる
'Dim str As String = "1"

'DayOfWeek列挙体に変換する
Dim dow As DayOfWeek = DirectCast([Enum].Parse(GetType(DayOfWeek), str), DayOfWeek)
C#
コードを隠すコードを選択
//変換する文字列
string str = "Monday";
//次のような数値を文字列にしたものも変換できる
//string str = "1";

//DayOfWeek列挙体に変換する
DayOfWeek dow = (DayOfWeek)Enum.Parse(typeof(DayOfWeek), str);

次のように、FlagsAttribute属性が適用された列挙体にも変換できます。

VB.NET
コードを隠すコードを選択
'変換する文字列。複数の値を持つ時は、コンマで区切る
Dim str As String = "Assembly, Struct"
'次のような数値を文字列にしたものも変換できる
'string str = "9";

'AttributeTargets列挙体に変換する
Dim at As AttributeTargets = _
    DirectCast([Enum].Parse(GetType(AttributeTargets), str), AttributeTargets)
C#
コードを隠すコードを選択
//変換する文字列。複数の値を持つ時は、コンマで区切る
string str = "Assembly, Struct";
//次のような数値を文字列にしたものも変換できる
//string str = "9";

//AttributeTargets列挙体に変換する
AttributeTargets at = (AttributeTargets)Enum.Parse(typeof(AttributeTargets), str);

Enum.Parseメソッドは文字列を列挙体に変換できない時に例外をスローしますが、.NET Framework 4.0以降で使用できるEnum.TryParseメソッドを使えば、例外をスローすることなく変換することができます。

VB.NET
コードを隠すコードを選択
'変換する文字列
Dim str As String = "Monday"

'DayOfWeek列挙体に変換できるか調べ、変換できれば変換する
Dim dow As DayOfWeek
If [Enum].TryParse(Of DayOfWeek)(str, dow) Then
    '変換できた時は、結果を表示する
    Console.WriteLine(dow)
Else
    '変換できなかった時
    Console.WriteLine("{0}をDayOfWeekに変換できません", str)
End If
C#
コードを隠すコードを選択
//変換する文字列
string str = "Monday";

//DayOfWeek列挙体に変換できるか調べ、変換できれば変換する
DayOfWeek dow;
if (Enum.TryParse<DayOfWeek>(str, out dow))
{
    //変換できた時は、結果を表示する
    Console.WriteLine(dow);
}
else
{
    //変換できなかった時
    Console.WriteLine("{0}をDayOfWeekに変換できません", str);
}

変換したい数値が列挙体として適切か調べる

今まで紹介してきた方法では、数値を列挙体に変換する時、その数値が列挙体に定義されている値かを考慮しません。たとえその数値が列挙体に定義されていない値であっても、列挙体に変換できてしまいます。

例えばDayOfWeek列挙体のメンバは、DayOfWeek.Sundayが0、DayOfWeek.Mondayが1というように、0から6までのいずれかの整数です。ところが、例えば7のように、この範囲外の整数をDayOfWeek列挙体にキャストすることもできてしまいます。

指定した数値が列挙体に定義された値であるかを調べるには、Enum.IsDefinedメソッドを使います。または、.NET Framework 4.0以降であれば、Type.IsEnumDefinedメソッドを使っても同じことができます。

以下に示す例では、数値を列挙体に変換する前に、Enum.IsDefinedメソッドで列挙体の値として適切かを調べています。

VB.NET
コードを隠すコードを選択
'変換する数値
Dim val As Integer = 1

'valがDayOfWeek列挙体のメンバの値として存在するか調べる
If [Enum].IsDefined(GetType(DayOfWeek), val) Then
    'DayOfWeek列挙体に変換する
    Dim dow As DayOfWeek = DirectCast(val, DayOfWeek)
End If
C#
コードを隠すコードを選択
//変換する数値
int val = 1;

//valがDayOfWeek列挙体のメンバの値として存在するか調べる
if (Enum.IsDefined(typeof(DayOfWeek), val))
{
    //DayOfWeek列挙体に変換する
    DayOfWeek dow = (DayOfWeek)val;
}

しかしこの方法では、FlagsAttribute属性が適用されている列挙体で、複数の値が組み合わされた値の場合は、それが列挙体の値として適切かを判断できません。

そこで、FlagsAttribute属性が適用されている列挙体でも、指定した値がその列挙体の値として適切かを調べることができるメソッドを作ってみました。メソッドは2つあり、一つはInt32型の値を調べ、もう一つはなんでも大丈夫なようにObject型にしてあります。指定された値が組み合わされた値かを調べる方法だけ両者で変えてあります(Object型の方法は、ちょっと野暮ったい方法になってしまいましたが)。

なおこれらのメソッドの使い方は、上のEnum.IsDefinedメソッドと同じです。

VB.NET
コードを隠すコードを選択
''' <summary>
''' 指定した値が列挙体の値として適切かを調べる
''' </summary>
''' <param name="enumType">列挙体の型</param>
''' <param name="value">Int32型の値</param>
''' <returns>列挙体の値として適切な時はtrue、適切でない時はfalse</returns>
Public Shared Function ValidateEnumValue(ByVal enumType As Type, _
                                         ByVal value As Integer) As Boolean
    'enumTypeが列挙体か確認
    If Not enumType.IsEnum Then
        Throw New ArgumentException("enumType")
    End If
    'valueが列挙体の基になる型と同じか確認
    If [Enum].GetUnderlyingType(enumType) <> GetType(Integer) Then
        Throw New ArgumentException("value")
    End If

    'valueが列挙体のメンバの値として定義されているか調べる
    If [Enum].IsDefined(enumType, value) Then
        Return True
    End If

    '列挙体にFlagsAttributeが適用されているか調べる
    If enumType.GetCustomAttributes(GetType(FlagsAttribute), False).Length = 0 Then
        Return False
    End If

    'FlagsAttributeが適用されている場合は、valueが組み合わされた値か調べる
    '列挙体のすべてのメンバの値を取得する
    Dim enumVals As Integer() = DirectCast([Enum].GetValues(enumType), Integer())
    'すべてのメンバ値を組み合わせた値を計算する
    Dim allVals As Integer = 0
    For Each v As Integer In enumVals
        allVals = allVals Or v
    Next
    'valueが列挙体のメンバ値の組み合わせか確認する
    If (allVals And value) = value Then
        Return True
    End If

    Return False
End Function

''' <summary>
''' 指定した値が列挙体の値として適切かを調べる
''' </summary>
''' <param name="enumType">列挙体の型</param>
''' <param name="value">指定する値</param>
''' <returns>列挙体の値として適切な時はtrue、適切でない時はfalse</returns>
Public Shared Function ValidateEnumValue(ByVal enumType As Type, _
                                         ByVal value As Object) As Boolean
    If Not enumType.IsEnum Then
        Throw New ArgumentException("enumType")
    End If
    If [Enum].GetUnderlyingType(enumType) <> value.GetType() Then
        Throw New ArgumentException("value")
    End If

    If [Enum].IsDefined(enumType, value) Then
        Return True
    End If

    If enumType.GetCustomAttributes(GetType(FlagsAttribute), False).Length = 0 Then
        Return False
    End If

    'valueが組み合わされた値であるか調べる
    'valueを列挙体に変換する
    Dim enumObj As Object = [Enum].ToObject(enumType, value)
    '列挙体を文字列に変換する
    Dim enumStr As String = enumObj.ToString()
    '文字列にコンマが含まれている時は、組み合わされた値と判断する
    If -1 < enumStr.IndexOf(","c) Then
        Return True
    End If

    Return False
End Function
C#
コードを隠すコードを選択
/// <summary>
/// 指定した値が列挙体の値として適切かを調べる
/// </summary>
/// <param name="enumType">列挙体の型</param>
/// <param name="value">Int32型の値</param>
/// <returns>列挙体の値として適切な時はtrue、適切でない時はfalse</returns>
public static bool ValidateEnumValue(Type enumType, int value)
{
    //enumTypeが列挙体か確認
    if (!enumType.IsEnum)
    {
        throw new ArgumentException("enumType");
    }
    //valueが列挙体の基になる型と同じか確認
    if (Enum.GetUnderlyingType(enumType) != typeof(int))
    {
        throw new ArgumentException("value");
    }

    //valueが列挙体のメンバの値として定義されているか調べる
    if (Enum.IsDefined(enumType, value))
    {
        return true;
    }

    //列挙体にFlagsAttributeが適用されているか調べる
    if (enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Length == 0)
    {
        return false;
    }

    //FlagsAttributeが適用されている場合は、valueが組み合わされた値か調べる
    //列挙体のすべてのメンバの値を取得する
    int[] enumVals = (int[])Enum.GetValues(enumType);
    //すべてのメンバ値を組み合わせた値を計算する
    int allVals = 0;
    foreach (int v in enumVals)
    {
        allVals |= v;
    }
    //valueが列挙体のメンバ値の組み合わせか確認する
    if ((allVals & value) == value)
    {
        return true;
    }

    return false;
}

/// <summary>
/// 指定した値が列挙体の値として適切かを調べる
/// </summary>
/// <param name="enumType">列挙体の型</param>
/// <param name="value">指定する値</param>
/// <returns>列挙体の値として適切な時はtrue、適切でない時はfalse</returns>
public static bool ValidateEnumValue(Type enumType, object value)
{
    if (!enumType.IsEnum)
    {
        throw new ArgumentException("enumType");
    }
    if (Enum.GetUnderlyingType(enumType) != value.GetType())
    {
        throw new ArgumentException("value");
    }

    if (Enum.IsDefined(enumType, value))
    {
        return true;
    }

    if (enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Length == 0)
    {
        return false;
    }

    //valueが組み合わされた値であるか調べる
    //valueを列挙体に変換する
    object enumObj = Enum.ToObject(enumType, value);
    //列挙体を文字列に変換する
    string enumStr = enumObj.ToString();
    //文字列にコンマが含まれている時は、組み合わされた値と判断する
    if (-1 < enumStr.IndexOf(','))
    {
        return true;
    }

    return false;
}

注意:この記事では、基本的な事柄の説明が省略されているかもしれません。初心者の方は、特に以下の点にご注意ください。

  • .NET Tipsをご利用いただく際は、注意事項をお守りください。