ないもの?
うわー、自分でも Delphi のコードかけなくてびっくり。これ大丈夫か(笑
type N = (A, B); // (1) 値が限定された順序型 Nx = set of N; // (2) そしてその集合型 procedure X(Nx flags, string prefix) // (4) 関数内関数 とか function GetName(N n): string; resourcestring NAMEofA = 'aaa'; // (3) コードに埋め込めるリソース識別子 NAMEofB = 'bbb'; // 当然、スコープごとに定義可能 begin case n of A: GetName := NAMEofA; B: GetName := NAMEofB; else // N 型が A と B しか取らないので // ここは到達不能コードであると認識される。 end; GetName := prefix + GetName; end; var i: N; begin for i := Low(N) to High(N) do begin if flags * [i] <> [] then // i in flags でも Console.WriteLine(GetName(i)) end; end;
.NET だとライブラリにある程度が押し出されちゃってるせいで、プロダクトの性質を無視してプログラム言語を自由に選択しやすいかもしれない。頑張れば VB 専門の技術者と C# な技術者のチームで混在コードで開発だってできちゃうし。そういう意味では多彩多用な言語が個々の方向性をもって頑張ってもらいたいところ。
だから、VB 使いは With とか Redim とか Erase とか、 Option Strict Off とか頑張って使ってほしいところだ。*1
ちょっとどうでもいいコードを書いてみたけど、やっぱ id:yaneurao:20051016 でも書いたけど (1) は欲しいな...。(2) (4) は比較的どうでもいいけど、FlagsAttribute に関してはもうすこしプログラム言語側にサポート機能があってもいいかもしれない。ParamArrayAttribute 並に言語に組み込まれてもいいと思うんだけど、1ビット単位じゃないフラグやマスクを定義する場所に困ったりして、そういう意味では FlagsAttribute だけではメタ情報が足りないんだろう。*2
そういえば、VB では OptionalAttribute(省略時デフォルト引数)もサポートしてるけど、C# ではサポートしていないし、.NET Framework の標準ライブラリもオーバーロード量産型である。CLS で禁止されてるんだっけ?と思ったけど、CLSCompliantAttribute つけても警告はでなかった。*3
Delphi や C++/CLI も魅力的だけど、当面は C# でいいや(笑
[Flags] // (2) 集合型としての言語サポートはない privat enum N // (1) マッピングする型が決まると { // その型の値は何でも入ってしまう。 A, B, } public void X(N flags, string prefix) { foreach (N flag in Enum.GetValues(typeof(N)) { if ((flags & flag) != 0) Console.WriteLine(GetName(flag, prefix)); } } // (4) 関数内関数はたいして需要ないな? // prefix はスコープが変わるので引数で引っ張った。 // メソッドコンテキストに収めなくていいならメンバに保持とか。 private string GetName(N flag, string prefix) { // (3) リソース識別子とコードの連携は困難 // InvariantCulture の実値等はフォームデザイナで設定でき // るので対して困らないが、識別子の管理はデザイン可能にし // ない限りできない。リソース依存メソッドの数だけコンポー // ネントを張るわけにもいかず手管理。 const string RES_NAMEofA = 'NAMEofA'; const string RES_NAMEofB = 'NAMEofB'; ResourceManager rm = new ResourceManager(typeof(xxx)); StringBuilder sb = new StringBuilder(); switch (flag) { case N.A: sb.Append(rm.GetString(RES_NAMEofA)); break; case N.B: sb.Append(rm.GetString(RES_NAMEofB)); break; default: throw new InvalidEnumException(); } }