ホームに戻る
出典 :
関連 :
目次 :
列挙型をビットフィールド(フラグセット)として用いる
[Flags]属性を付与することで、列挙型をフラグとして用いることができるようになる。
その際、各列挙子は 0 または2のべき乗でなければならない。
(コード例)
using System;
class Example
{
// Flags 属性無しの列挙体定義
enum SingleHue : short
{
None = 0,
Black = 1,
Red = 2,
Green = 4,
Blue = 8,
};
// Flags 属性つきの列挙体定義
[Flags]
enum MultiHue : short
{
None = 0,
Black = 1, //< 2 ^ 0
Red = 2, //< 2 ^ 1
Green = 4, //< 2 ^ 2
Blue = 8, //< 2 ^ 3
};
static void Main( )
{
Console.WriteLine( "SingleHue :" );
for(int val = 0; val <= 16; val++ )
Console.WriteLine( $"{val} - {( (SingleHue)val ).ToString()}" );
Console.WriteLine( "" );
Console.WriteLine( "MultiHue :" );
for( int val = 0; val <= 16; val++ )
Console.WriteLine( $"{val} - {( (MultiHue)val ).ToString()}" );
}
}
(出力結果)
SingleHue :
0 - None
1 - Black
2 - Red
3 - 3
4 - Green
5 - 5
6 - 6
7 - 7
8 - Blue
9 - 9
10 - 10
11 - 11
12 - 12
13 - 13
14 - 14
15 - 15
16 - 16
MultiHue :
0 - None
1 - Black
2 - Red
3 - Black, Red //< 1 + 2
4 - Green
5 - Black, Green //< 1 + 4
6 - Red, Green //< 2 + 4
7 - Black, Red, Green //< 1 + 2 + 4
8 - Blue
9 - Black, Blue //< 1 + 8
10 - Red, Blue //< 2 + 8
11 - Black, Red, Blue //< 1 + 2 + 8
12 - Green, Blue //< 4 + 8
13 - Black, Green, Blue //< 1 + 4 + 8
14 - Red, Green, Blue //< 2 + 4 + 8
15 - Black, Red, Green, Blue //< 1 + 2 + 4 + 8
16 - 16
Flags 属性の無い SingleHue は、定義されたシンボルのみが文字列として出力されているが、
Flags 属性を付与した MultiHue は、セットされたビットに対応するシンボルすべてを出力している。
Enumに対するビット演算
// ビット論理和
MultiHue color = MultiHue.Black | MultiHue.Green; //< Black, Green
// ビットセット
color |= MultiHue.Red; //< Black, Red, Green
// ビットクリア
color &= ~MultiHue.Green; //< Black, Red
// フラグの確認 (HasFlag() メソッド)
if ( color.HasFlag(MultiHue.Black) )
{
Console.WriteLine ("Black included");
}
// フラグの確認 (AND演算・上記と等価)
if ( color & MultiHue.Black )
{
Console.WriteLine ("Black included");
}
特定のビット(フラグ)がセットされていることはAND演算、または HasFlag() メソッドにより確認できる。
但し、HasFlag() は値型(enum)を参照型(Enum)にボックス化するため、パフォーマンスへの影響が発生する。
列挙子と文字列リテラル
列挙子に対して ToString() を実行すると、基となる値ではなくラベルが取得できる。
このため列挙子を複合文字列、または文字列補完に含めた場合はラベルが埋め込まれる。
( ToString() を暗黙的にコールしているため。ToString() をオーバーロードすることで異なる出力を得ることもできる。)
using System;
public class Sample
{
// 列挙型の定義
enum Colors { Red, Green, Blue, Yellow };
public static void Main()
{
Colors c1 = Colors.Blue;
Colors c2 = Colors.Red;
// 複合文字列
Console.WriteLine( "c1 は {0} です。", c1 );
// 文字列補完
Console.WriteLine( $"c2 は {c2} です。" );
}
}
// 出力結果 :
// c1 は Blue です。
// c2 は Red です。
列挙子の要素名(ラベル)の取得 : GetName() / ToString()
string? Enum.GetName(Type enumType, object value)
値 value が列挙型 enumType に含まれる場合に、対応する列挙子のラベルを文字列形式で返却する。
value が enumType に含まれない場合は null を返す。
using System;
public class Sample
{
// 列挙型の定義
enum Colors { Red, Green, Blue, Yellow };
public static void Main()
{
// 値 3 に相当するラベルを取得、画面に表示
// ⇒ lbl = "Yellow" となる
string lbl = Enum.GetName( typeof( Colors ), 3 );
Console.WriteLine( $"列挙体 Colors において 3 に相当するラベルは {lbl} です。" );
}
}
// 出力結果 :
// 列挙体 Colors において 3 に相当するラベルは Yellow です。
注意が必要な点
value で指定された値が複数のメンバに該当する(複数のメンバが同じ値を持つ)場合、GetName() はそのうちのいずれかを返すが、いずれのメンバが返されるかは不定である。
(尤も、値が重複するような用途はそもそも適切ではない。)
string? Enum.GetName<TEnum>(TEnum value)
列挙値 value のラベルを文字列形式で返却する。
using System;
public class Sample
{
// 列挙型の定義
enum Colors { Red, Green, Blue, Yellow };
public static void Main()
{
// Colors.Green のラベルを取得、画面に表示
// ⇒ "Green" が表示される
Colors col = Colors.Green;
string lbl = Enum.GetName( col );
Console.WriteLine( lbl );
}
}
// 出力結果 :
// Green
string ToString()
列挙値のラベルを文字列形式で返却する。
using System;
public class Sample
{
// 列挙型の定義
enum Colors { Red, Green, Blue, Yellow };
public static void Main()
{
// Colors.Green のラベルを取得、画面に表示
// ⇒ "Green" が表示される
Colors col = Colors.Green;
string lbl = col.ToString();
Console.WriteLine( lbl );
}
}
// 出力結果 :
// Green
Enum.GetName() との差異
Enum.GetName() は引数で指定された値が列挙型に含まれない場合に null を返すが、ToString() は String.Empty を返す。
null を考慮する必要が無いため、ToString() はより簡便に用いることができる。
値または要素名(ラベル)の集合の取得 : GetValues() / GetNames()
Enum の静的メソッド GetValues() 、GetNames() を用いることで、引数に指定した列挙型のすべての値、またはすべてのラベルを集合として取得することができる。
これにより、列挙型に対する繰り返し処理( foreach )を行うことができる。尚、引数には列挙型の型情報( typeof(...) )を与える。
GetValues() : 値の抽出
コード :
using System;
namespace Sample
{
// 列挙型の定義
enum E_Name
{
Himurock = 0,
Kikkawa = 1,
Hotei = 2,
}
// サンプルクラス
class Sample
{
static void Main()
{
// 列挙型 E_Name に対する foreach
// Enum.GetValues() で値の集合を抽出する
foreach (E_Name val in Enum.GetValues(typeof(E_Name)))
{
// Enum.GetName() で値から名前を得る
string name = Enum.GetName(typeof(E_Name), val);
Console.WriteLine($"{name} : {(int)val}");
}
}
}
}
実行結果 :
Himurock : 0
Kikkawa : 1
Hotei : 2
Enum.GetValues() および Enum.GetName() の引数に typeof(E_Name) を指定している点に注意。
これは後述の Enum.GetNames() も同様である。
GetNames() : ラベルの抽出
コード :
using System;
namespace Sample
{
// 列挙型の定義
enum E_Name
{
Himurock = 0,
Kikkawa = 1,
Hotei = 2,
}
// サンプルクラス
class Sample
{
static void Main()
{
// 列挙型 E_Name に対する foreach
// Enum.GetNames() でラベルの集合を抽出する
foreach (string name in Enum.GetNames(typeof(E_Name)))
{
Console.WriteLine(name);
}
}
}
}
実行結果 :
Himurock
Kikkawa
Hotei
Enum.GetNames() の戻り値は string[] 。
指定した値が列挙体に含まれるかを確認する : IsDefined()
指定した値が列挙型に含まれる場合に true 、そうでない場合に false を返す。
int unknown = -1;
if (Enum.IsDefined(typeof(Colors), unknown))
{
// unknown(-1) が Colors のメンバに含まれていればここを通る
}
指定した値を列挙オブジェクトに変換する : Parse() / TryParse()
Parse() は指定した値が列挙体に変換可能( IsDefined() == true )ならば変換を実行、変換できない場合は例外を発する。
TryParse() は変換が可能であれば変換を行うとともに true を返し、変換できなければ false を返す。
いずれも複数のオーバーロードが存在するが、ここでは代表的なもののみを紹介する。
// MultiHue に Black が含まれていれば result1 は MultiHue.Black と等価、
// そうでなければ例外
object result1 = Enum.Parse(typeof(MultiHue), "Black");
// MultiHue に Green が含まれていれば result2 は MultiHue.Green 、
// そうでなければ例外
MultiHue result2 = Enum.Parse<MultiHue>("Green");
// MultiHue に Blue が含まれていれば result3 は MultiHue.Blue と等価、
// そうでなければ null となる
bool succeed = Enum.TryParse(typeof(MultiHue), "Blue", out object? result3);
// MultiHue に Red が含まれていれば result4 は MultiHue.Red 、
// そうでなければ MultiHue の既定値となる
bool succeed = Enum.TryParse<MultiHue>("Red", out MultiHue result4);
|
変換成功時 (戻り値) |
変換失敗時 |
Parse() |
object 型 |
ArgumentException |
Parse<TEnum>() |
TEnum 型 |
|
out引数の型 |
変換成功時 |
変換失敗時 |
out引数の値 |
戻り値 |
out引数の値 |
戻り値 |
TryParse() |
object 型 |
対応する列挙オブジェクト |
true |
null |
false |
TryParse<TEnum>() |
TEnum 型 |
TEnum の既定値 |