プロパティの整合性確認
菊池さんのところ C# Tips: Enumなプロパティのsetterの冒頭はより、内容は問題ないのだが、プロパティはフィールドの延長として型チェック程度に留め、その値を使う時に始めて問題を発生させるべきであるという点が薄まってしまわないかという懸念。
分かりにくいし良い例もすぐに思いつかないのだが、次のようなコードを書いてはならない。
public enum SignalTypes { Bicolored, // 赤青二色信号 Tricolored, // 赤青黄三色信号 } public enum SignalColors { Red, // 赤信号=通行禁止 Stop, // 黄信号=止まれ Green, // 青信号=通行許可 } public class Signal { public SignalTypes Type { get { return this.type; } set { if (!Enum.IsDefined(value, typeof(SignalTypes)) throw new InvalidEnumArgumentException("Type", (int) value, typeof(SignalTypes)); this.type = value; } } public SignalColors Color { get { return this.color; } set { if (!Enum.IsDefined(value, typeof(SignalColors)) throw new InvalidEnumArgumentException("Color", (int) value, typeof(SignalColors)); if ((this.Type == SignalTypes.Bicolored) && (value == SignalColors.Stop)) throw new ArgumentException(); this.color = value; } } }
Color プロパティの設定がフィールドの延長としての型チェックを逸脱し、自身のインスタンスがもつ Type というコンテキスト情報に依存した実装になってしまっている。これは .NET のコンポーネントデザインルールに反しているため、*1このようなプロパティを持つコンポーネントは Visual Studio .NET を始めとする多くのヴィジュアルデザイナや 2-way デザイナによって扱うことができない。*2
FlagsAttribute の付与されていない場合は、余計なチェックを行わないだけで解決するかもしれないが、FlagsAttribute のついた場合はちょっとややこしい話になる。特定のフラグ同士の組み合わせが可能であるか排他であるかといった考え方をするとき、どうしても特定のコンテキストに依存して組み合わせが排他になる組み合わせを排除しようとしてしまうのである。
そうそう、.NET Framework ではプロパティの設定コードが set_PROPERTY(TYPE value) に展開され、.NET 対応言語によってはプロパティの設定として、明示的にこのメソッドを呼び出すことを考慮して、例外のパラメータ名を value としている。しかし、クラスのメタデータにプロパティが定義されている場合は、上記のようにプロパティ名を指定してもいいんじゃないかと思うんだけど、どうだろう?