ある値が複数の意味を持つ場合、それぞれのビットに意味を持たせる。
C/C++ 等では定数を定義して、unsigned int 等と組み合わせて使う。.NET では FlagsAttribute と enum を組み合わせて使えるので便利だ。
私は FlagsAttribute を割と頻繁に使うのだが、これが分かりにくいというクレームを受けた。例えば以下のようにしていたとしよう。
[Flags]
public enum TestFlags {
A = 0x1,
B = 0x2,
C = 0x4
}
public class TestClass {
public TestFlags Flag;
}
クレームをつけた本人は理解しているのだが、「ビット演算は難しい。使用法を間違う人もいる。それぞれをプロパティで持たせればよい」と言った。例えば以下のように。
public class TestClass {
public bool EnableA;
public bool EnableB;
public bool EnableC;
}
確かに一理ある。しかし「間違う人がいるか?こんなのが分からないという人は、(言語仕様の一部なのだから)if 文が分からないと言っているのと一緒だ」と思ったが、現にビット演算がよく分からなくて変なコードを書く人がいる。
以下のように 2 つの変数があり、一方がもう一方にに立っているビットの少なくとも一つがあるかをチェックしたいときは、 if 文 1 つで済む、というのが私の言い分だ。
public void Func1() {
TestClass t1 = new TestClass();
TestClass t2 = new TestClass();
if ((t1.Flag & t2.Flag) != 0) {
}
}
相手の言い分は、例えば以下のように書くのは違和感があるという事だ。
public void Func2() {
TestClass test = new TestClass();
checkBox1.Checked = (test.Flag & TestFlags.A) != 0;
checkBox1.Checked = (test.Flag & TestFlags.B) != 0;
checkBox1.Checked = (test.Flag & TestFlags.C) != 0;
}
上記を次のように書けた方がよい。
public void Func2() {
TestClass test = new TestClass();
checkBox1.Checked = test.EnableA;
checkBox1.Checked = test.EnableB;
checkBox1.Checked = test.EnableC;
}
私はどちらの書き方でも何の違和感もないし、Flag である事がわかるなら、前者の方がいいぐらいだ。
…で、家への帰路の間考えていたが、やはり私の方が間違っていて、フィールドやプロパティに FlagsAttribute の enum は持たせない方がよいのではないか、と考え直した。
オブジェクト指向言語では、フィールドやプロパティを幾らでもオブジェクトに持たせる事ができるのに、わざわざ一つのプロパティに複数の意味を持たせる必要はない。
では、FlagsAttribute の enum はいつ使われるのか。
恐らく、メソッドへの引数が唯一の正確な使用法なのだろう。