.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行のシンプルな条件文へ、すっきりと短く分かりやすくなっている。End of Article

カテゴリ:クラス・ライブラリ 処理対象:列挙体
使用ライブラリ:Enumクラス(System名前空間)

この記事と関連性の高い別の.NET TIPS
整数や文字列を列挙体に変換するには?[C#/VB]
このリストは、(株)デジタルアドバンテージが開発した
自動関連記事探索システム Jigsaw(ジグソー) により自動抽出したものです。
generated by

「.NET TIPS」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間