C# と VB.NET の質問掲示板

わんくま同盟

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト


(過去ログ 149 を表示中)
■86934 / )  Re[1]: フラグを操作するジェネリックメソッドを作る方法
□投稿者/ 魔界の仮面弁士 (1600回)-(2018/04/04(Wed) 11:57:49)
No86903 (MTK さん) に返信
> Whereを加えることで制約を付けることができるとあったのですが、この場合はどのような制約をかければ対応ができるのでしょうか?

Where ではなく where ですね。

列挙型は型制約として指定できないので、struct で代用しておいた上で
さらにメソッド内で Type.IsEnum による型チェックを施す感じでしょうか。


public static class BitFlagHelper
{
 public static void SetFlag<TEnum>(ref this TEnum self, TEnum flag) where TEnum : struct
 {
  System.Diagnostics.Debug.Assert(typeof(TEnum).IsEnum);
  var bits = Convert.ToUInt64(self) | Convert.ToUInt64(flag);
  self = (TEnum)System.Enum.ToObject(typeof(TEnum), bits);
 }
}


> // 指定されたフラグを加算するメソッド
> public static void AddFlag(ref FlagEnumA flag, FlagEnumA state)

プロパティが公開されているなら、そのまま
 objClassA.PropA |= FlagEnumA.Enable;
の方が素直だとは思います。

しかし今回は、ビットフラグの操作に慣れていない利用者に向けて、
 FlagOperator.AddFlag(ref objClassA.PropA, FlagEnumA.Enable);
のようなメソッドを作りたい…と事情であろうかと推察します。


しかし、ジェネリックを使うかどうかは抜きにしても、そもそも
C# では、ref や out な引数にプロパティを渡せない仕様なので、
残念ながらそういうことはできません。


たとえば上記の BitFlagHelper を呼ぶにしても、
  BitFlagHelper.SetFlag(ref objClassA.PropA, FlagEnumA.Visible);
のような呼び出しは許可されていないので、受け渡し用の変数が必要になってしまいます。

  var propA = objClassA.PropA; // ref で渡すための変数
  //「propA.SetFlag(FlagEnumA.Visible);」でも可
  BitFlagHelper.SetFlag(ref propA, FlagEnumA.Visible);
  objClassA.PropA = propA;



Visual Basic であれば、ByRef 引数へのプロパティ渡しが禁止されていないので、上記を
  'objA.PropA = objA.PropA Or FlagEnumA.Visible
  BitFlagHelper.AddFlag(objA.PropA, FlagEnumA.Enable)
のように呼び出せるのですけれどね…。



> これらの機能をまとめた汎用クラスを作っておけば楽かなと思ったためです。
ジェネリック クラスのかわりに、拡張メソッドを使うのはどうでしょうか。

たとえば DateTime 型の Add 何某メソッドは、「日付の加減算結果を返す」メソッドであり、
  dateTimePicker1.Value = dateTimePicker1.Value.AddDays(1); // 翌日の日付に変更
などのように書けますが、それを真似て
 objClassA.PropA = objClassA.PropA.SetFlag(FlagEnumA.Visible); // Visible フラグを立てる
などと書ける様な SetFlag 拡張メソッドを追加するなど。


あるいは汎用化に拘らず、クラスA 自身に
 public bool this[FlagEnumA flag]
 {
  get { return this.PropA.HasFlag(flag); }
  set { if (value) { this.PropA |= flag; } else { this.PropA &= ~flag; } }
 }
のようなインデクサを用意して、利用する側から
 objClassA[FlagEnumA.Visible] = true;
のようにしてビットフラグを読み書きできるようにしておくとか。
今回の目的からは離れてしまいますけれども。
解決済み
返信 編集キー/


管理者用

- Child Tree -