Yuta.NET

C#のenumをビットフラグとしてスマートに扱う小技


定数で且つグループ化できるものはenumを使った方が良い (というか使ってくれ...orz)

また、enumは色々と工夫次第で便利になります。
ここでは拡張メソッドを使った小技を紹介しますので上手く応用して可読性を上げよう!!

下のコードはenumをビットフラグとして扱っています。
また、ビット演算を行うことにより複数のフラグを保持してスマートに扱う方法を記載しています。

因みに動きが見やすいように2進数で扱っていますが必要に応じて16進数や10進数で扱っても問題無いです。
また、コピペして動作確認が行いやすいように全文記載しているため、長いですが必要箇所だけ見ればOK


using System;
using System.Linq;

namespace YutaCore.ConsoleApp1
{
    [Flags]
    enum Product : byte
    {
        None       = 0,
        Apple      = 1 << 0,
        Orange     = 1 << 1,
        Meron      = 1 << 2,
        Strawberry = 1 << 3,
    }

    class Program
    {
        static void Main(string[] args)
        {
            string name = string.Empty;
            // 整形用に最大文字数を取得(注:この記述のLinqは.NET3.5以上で使用可)
            int maxLength = Enum.GetNames(typeof(Product)).Max(v => v.Length);

            // foreachでEnumの全ての列挙子(値)を取得
            foreach (Product value in Enum.GetValues(typeof(Product)))
            {
                // 固定幅で名称を取得
                name = string.Format("{0, -" + maxLength + "}", value.ToString());
                // 2進数で4bitのみ表記
                Console.WriteLine("{0}: {1}", name, Convert.ToString((byte)value, 2).PadLeft(4, '0'));
            }

            Console.WriteLine("\n**** カートに入っている商品 ****");
            Product cart = Product.Orange | Product.Meron;
            Console.WriteLine("{0}: {1}", cart, Convert.ToString((byte)cart, 2).PadLeft(4, '0'));
            Console.WriteLine("--------");

            foreach (Product value in Enum.GetValues(typeof(Product)))
            {
                if (cart == Product.None)
                {
                    Console.WriteLine("カートには何も入っていません。");
                    break;
                }

                if (value == Product.None) continue;

                // 速度重視ならこの書き方のほうが良い
                // if ((cart & value) == value)

                // 基本的には可読性重視で良いかと...(注:この記述のHasFlagは.NET4.0以上で使用可)
                if (cart.HasFlag(value))
                {
                    Console.WriteLine("{0}が入っています。", value.ToString());
                }
            }
            Console.WriteLine("********************************");
            Console.ReadKey(true);
        }
    }
}