|   | 
 
|  
 .NET TIPS 
列挙体をビット・フィールドとして取り扱うには?[C#、VB]
デジタルアドバンテージ 一色 政彦 
2010/08/26 | 
  | 
 
 
  | 
 引数としてフラグ(あるいはオプション)を受け取るメソッドを作る場合がある。例えば、引数がtrueであれば「Aモード」で実行し、falseがあれば「Bモード」で実行するといったように、引数の値によって挙動を変えるようなメソッドである。 
 こういったフラグ・パラメータとしては、2つのモード間での切り替えであればtrue/falseのBoolean型が使えるが、フラグが複数になってくるとEnum型を使う場合が多い。ただし通常のEnum型は、1つの値しか保持できないので、1つの引数で複数のフラグを組み合わせることはできない。 
 Enum型では、Flags属性(=FlagsAttributeクラス)を付与することで、そのEnum型が、「ビットごとのOR演算」が行えるビット・フィールドとして使えるようになる。これにより、1つの値で複数のフラグの組み合わせを扱える。 
 例えば.NET  Framework 2.0以降の基本クラス・ライブラリでは、ConsoleModifiers列挙体(System名前空間)がビット・フィールドとなっており、[Shift]キー、[Alt]キー、[Ctrl]キーのさまざまな組み合わせを、1つのConsoleModifiers値で表現できる。 
 次のコードは、実際に独自のEnum型にFlags属性を付与してビット・フィールドとして取り扱うコンソール・アプリケーションのサンプルである。 
using System; 
 
// Enum型をビット・フィールド化 
[Flags] 
public enum SampleOptions 
{ 
  A = 0x00, 
  B = 0x01, 
  C = 0x02, 
} 
 
class Program 
{ 
  static void Main(string[] args) 
  { 
    // SampleOptionsの「A」と「C」を組み合わせて1つの値を作成 
    SampleOptions opt = SampleOptions.A | SampleOptions.C; 
 
    // SampleOptions値に「A」と「C」が含まれているかを調べる 
    if (((opt & SampleOptions.A) == SampleOptions.A) && 
        ((opt & SampleOptions.C) == SampleOptions.C)) 
    { 
      Console.WriteLine("AとCのフラグが含まれています。"); 
    } 
    // 出力例: 
    // AフラグとCフラグが含まれています。 
 
    Console.ReadLine();   // 実行を停止 
  } 
}  | 
 
 
' Enum型をビット・フィールド化 
<Flags()> _ 
Public Enum SampleOptions 
  A = &H0 
  B = &H1 
  C = &H2 
End Enum 
 
Module Module1 
 
  Sub Main() 
    ' SampleOptionsの「A」と「C」を組み合わせて1つの値を作成 
    Dim opt As SampleOptions = SampleOptions.A Or SampleOptions.C 
 
    ' SampleOptions値に「A」と「C」が含まれているかを調べる 
    If (opt And SampleOptions.A) = SampleOptions.A AndAlso _ 
      (opt And SampleOptions.C) = SampleOptions.C Then 
      Console.WriteLine("AとCのフラグが含まれています。") 
    End If 
    ' 出力例: 
    ' AフラグとCフラグが含まれています。 
 
    Console.ReadLine()   ' 実行を停止 
  End Sub 
 
End Module  | 
 
  | 
| 独自のEnum型にFlags属性を付与してビット・フィールドとして取り扱う例(上:C#、下:VB) | 
 上記のコードを見ると、複数のフラグを組み合わせて1つのSampleOptions値を作成する際には「ビットごとのOR演算子」を用い、逆にSampleOptions値に含まれているフラグを調べる(以降、フラグ判定)には「ビットごとのAND演算子」を用いればよいことが分かる。 
 フラグ判定において、上記のコード例では「A」と「C」の2つのフラグが両方とも含まれているかを調べているが、そのフラグ判定で調べるフラグの数が、例えば10個などと膨大になったり、あるいはその組み合わせパターンが数多くなったりしてくると、次第にその判定処理コードは煩雑で冗長になってきてしまう(可能性がある)。この問題を回避するために、.NET Framework 4のEnum型にはHasFlagメソッドが追加された。 
 HasFlagメソッドのパラメータには、調べたいフラグの組み合わせ(=ビットごとのOR演算。もちろん1つのフラグのみでも指定可能)で作成された(Enum型の)値を指定する。戻り値として、そのフラグの組み合わせがすべて含まれていればtrueを、1つでも含まれていないとfalseを返す。 
 次のコードは、上記のフラグ判定のコード個所をHasFlagメソッドに置き換えた例である(該当個所のみ抜粋)。 
if (opt.HasFlag(SampleOptions.A | SampleOptions.C)) 
{ 
  Console.WriteLine("AとCのフラグが含まれています。"); 
}  | 
 
 
If opt.HasFlag(SampleOptions.A Or SampleOptions.C) Then 
  Console.WriteLine("AとCのフラグが含まれています。") 
End If  | 
 
  | 
| (.NET Framework 4で追加された)HasFlagメソッドを用いたフラグ判定(上:C#、下:VB) | 
 HasFlagメソッドを使わないコード例では2行にわたっていた冗長なフラグ判定が、HasFlagメソッドを使った場合は1行のシンプルな条件文へ、すっきりと短く分かりやすくなっている。
 
カテゴリ:クラス・ライブラリ 処理対象:列挙体 
使用ライブラリ:Enumクラス(System名前空間) | 
 
|  
 | 
 
generated by  
 | 
 
 
 | 
 
 
	
		Insider.NET 記事ランキング
		
		
			本日
			月間