ここでは、数値を列挙体の値に変換する方法と、列挙体のメンバの名前や値を示す文字列を列挙体の値に変換する方法を紹介します。
数値を列挙体の値に変換するには、キャストをします。または、Enum.ToObjectメソッドを使います。
以下の例では、Int32型の数値をDayOfWeek列挙体の値に変換しています。
'変換する数値 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"と表示される
//変換する数値 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列挙体の値に変換しています。
'変換する数値 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"と表示される
//変換する数値 int val = 9; AttributeTargets at = (AttributeTargets)val; AttributeTargets at2 = (AttributeTargets)Enum.ToObject(typeof(AttributeTargets), val); Console.WriteLine(at); //"Assembly, Struct"と表示される
列挙体のメンバ名や値を示す文字列を列挙体の値に変換するには、Enum.Parseメソッドを使います。変換できる文字列は、列挙体のメンバの名前か、列挙体を示す数値の文字列です。
以下に、文字列をDayOfWeek列挙体に変換する例を示します。
'変換する文字列 Dim str As String = "Monday" '次のような数値を文字列にしたものも変換できる 'Dim str As String = "1" 'DayOfWeek列挙体に変換する Dim dow As DayOfWeek = DirectCast([Enum].Parse(GetType(DayOfWeek), str), DayOfWeek)
//変換する文字列 string str = "Monday"; //次のような数値を文字列にしたものも変換できる //string str = "1"; //DayOfWeek列挙体に変換する DayOfWeek dow = (DayOfWeek)Enum.Parse(typeof(DayOfWeek), str);
次のように、FlagsAttribute属性が適用された列挙体にも変換できます。
'変換する文字列。複数の値を持つ時は、コンマで区切る Dim str As String = "Assembly, Struct" '次のような数値を文字列にしたものも変換できる 'string str = "9"; 'AttributeTargets列挙体に変換する Dim at As AttributeTargets = _ DirectCast([Enum].Parse(GetType(AttributeTargets), str), AttributeTargets)
//変換する文字列。複数の値を持つ時は、コンマで区切る string str = "Assembly, Struct"; //次のような数値を文字列にしたものも変換できる //string str = "9"; //AttributeTargets列挙体に変換する AttributeTargets at = (AttributeTargets)Enum.Parse(typeof(AttributeTargets), str);
Enum.Parseメソッドは文字列を列挙体に変換できない時に例外をスローしますが、.NET Framework 4.0以降で使用できるEnum.TryParseメソッドを使えば、例外をスローすることなく変換することができます。
'変換する文字列 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
//変換する文字列 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メソッドで列挙体の値として適切かを調べています。
'変換する数値 Dim val As Integer = 1 'valがDayOfWeek列挙体のメンバの値として存在するか調べる If [Enum].IsDefined(GetType(DayOfWeek), val) Then 'DayOfWeek列挙体に変換する Dim dow As DayOfWeek = DirectCast(val, DayOfWeek) End If
//変換する数値 int val = 1; //valがDayOfWeek列挙体のメンバの値として存在するか調べる if (Enum.IsDefined(typeof(DayOfWeek), val)) { //DayOfWeek列挙体に変換する DayOfWeek dow = (DayOfWeek)val; }
しかしこの方法では、FlagsAttribute属性が適用されている列挙体で、複数の値が組み合わされた値の場合は、それが列挙体の値として適切かを判断できません。
そこで、FlagsAttribute属性が適用されている列挙体でも、指定した値がその列挙体の値として適切かを調べることができるメソッドを作ってみました。メソッドは2つあり、一つはInt32型の値を調べ、もう一つはなんでも大丈夫なようにObject型にしてあります。指定された値が組み合わされた値かを調べる方法だけ両者で変えてあります(Object型の方法は、ちょっと野暮ったい方法になってしまいましたが)。
なおこれらのメソッドの使い方は、上のEnum.IsDefinedメソッドと同じです。
''' <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
/// <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; }
注意:この記事では、基本的な事柄の説明が省略されているかもしれません。初心者の方は、特に以下の点にご注意ください。