43


10

flags属性が設定されている(またはより正確にはビット操作に使用されている)列挙型のスイッチを入れるにはどうすればよいですか?

宣言された値と一致するスイッチですべてのケースをヒットできるようにしたいです。

問題は、私は次の列挙型を持っている場合です

[Flags()]
パブリック列挙型CheckType {Form = 1、QueryString = 2、TempData = 4、}

こんなスイッチを使いたい

switch(theCheckType){case CheckType.Form:DoSomething(/ *何らかのタイプのコレクションが渡されます* /);}ブレーク;

case CheckType.QueryString:DoSomethingElse(/ *他の種類のコレクションが渡されます* /);ブレーク;

case CheckType.TempData DoWhatever(/ *異なるタイプのコレクションが渡されます* /)。ブレーク; }

"theCheckType"が両方のCheckTypeに設定されている場合。 CheckType.TempData両方のケースをヒットさせたいのですが。 明らかにそれはブレークのために私の例では両方ともヒットしませんが、それ以外はCheckType.FormがCheckType.Formと等しくないため失敗しますCheckType.TempData

私が見ることができるようにそれから唯一の解決策は列挙値のあらゆる可能な組み合わせのためにケースを作ることであるか?

何かのようなもの

ケースCheckType.Form | CheckType.TempData:DoSomething(/ *何らかの種類のコレクションが渡されます* /); DoWhatever(/ *何らかの異なる種類のコレクションが渡される* /);ブレーク;

ケースCheckType.Form | CheckType.TempData | CheckType.QueryString:DoSomething(/ *何らかの種類のコレクションが渡されます* /); DoSomethingElse(/ *他の種類のコレクションが渡されます* /);ブレーク;

... and so on...

しかし、それは実際にはあまり望ましくありません(すぐに非常に大きくなるため)。

今のところ私は3つの条件がお互いの後で代わりに

何かのようなもの

if((_CheckType

if((_CheckType
しかしそれはまた、私が20個の値を持つenumを持っているならば、スイッチを使うときのように必要な "case"だけに "ジャンプ"する代わりに、毎回20 If条件を通らなければならないことを意味します。

この問題を解決するための魔法のような解決策はありますか?

宣言された値をループ処理してからスイッチを使用することを考えていますが、宣言された値ごとにスイッチがヒットするだけですが、それがどのように機能するのかわかりません。 ifの多くと比較して)?

宣言されたすべてのenum値をループ処理する簡単な方法はありますか?

ToString()を使用して "、"で分割した後、配列をループしてすべての文字列を解析することしかできません。

'' '' '

更新:

私は説明するのに十分な仕事をしていないようです。 私の例は単純なものです(私のシナリオを単純化しようとしました)。

Asp.net MVCのActionMethodSelectorAttributeにこれを使用して、URL /ルートを解決するときにメソッドを使用できるかどうかを判断します。

私はメソッド上でこのような何かを宣言することによってそれを行います

public ActionResult Index(){return View();} }

つまり、FormまたはTempDataに、メソッドが使用可能になるように指定されたキーがあるかどうかを確認する必要があります。

それが呼び出すメソッド(前の例ではdoSomething()、doSomethingElse()およびdoWhatever())は実際には戻り値としてboolを持ち、パラメータを使用して呼び出されますused  - 下のリンクにある私のサンプルコードなどを参照してください。

うまくいけば私は何をしているのより良いアイデアを与えるために私は私が実際にpastebinでやっていることの簡単な例を貼り付けました - それはここhttp://pastebin.com/m478cc2b8で見つけることができます

8 Answer


43


これはどう。 もちろん、DoSomethingなどの引数と戻り値の型は、好きなものにすることができます。

クラスProgram {[Flags] public enum CheckType {Form = 1、QueryString = 2、TempData = 4、}

プライベート静的ブールDoSomething(IEnumerable cln){Console.WriteLine( "DoSomething"); trueを返します。 }

プライベート静的ブールDoSomethingElse(IEnumerable cln){Console.WriteLine( "DoSomethingElse"); trueを返します。 }

プライベート静的ブールDoWhatever(IEnumerable cln){Console.WriteLine( "DoWhatever"); trueを返します。 }

static void Main(string [] args){var theCheckType = CheckType.QueryString | int} CheckType.TempData; var checkTypeValues = Enum.GetValues(typeof(CheckType)); foreach(checkTypeValuesのCheckType値){if((theCheckType


13


Flags列挙型は、個々のビットがフラグ付きの値の1つに対応する単純な整数型として扱うことができます。 このプロパティを利用して、ビットフラグ付きの列挙値をブール値の配列に変換してから、関連するデリゲートの配列から対象のメソッドをディスパッチできます。

編集: _ LINQといくつかのヘルパー関数を使うことでこのコードをもっとコンパクトにすることができるかもしれませんが、洗練されていない形式の方が理解しやすいと思います。 保守性が優雅さを上回る場合がこれに該当します。

これが一例です。

[Flags()]
パブリック列挙型CheckType {Form = 1、QueryString = 2、TempData = 4、}

void PerformActions(CheckType c){//パラメータに設定されたビットの配列{c} bool [] actionMask = {false、false、false}; //呼び出すことができる対応するアクションへのデリゲートの配列... アクションavailableActions = {DoSomething、DoSomethingElse、DoAnotherThing};

//(int i = 0; i <actionMask.Length; i)に対するactionMask [i] =(c)

//各設定フラグに対して、(int actionIndex = 0; actionIndex <actionMask.Length; actionIndex){if(actionMask [actionIndex])availableActions [actionIndex]();に対応するアクションメソッドを送出します。 //対応するアクションを起動します}}

あるいは、あなたが評価する順番が重要ではない場合、ここでも同様に機能する、より簡単で明確な解決策が得られます。 順序が重要な場合は、ビットシフト演算を、評価したい順序でフラグを含む配列に置き換えます。

int flagMask = 1 << 31; //上位ビットから始めます... while(flagMask!= 0)//すべてのフラグが比較されるとループは終了します{// 1ビットだけオンにします... switch(theCheckType

case CheckType.QueryString:DoSomethingElse(/ *他の種類のコレクションが渡されます* /);ブレーク;

case CheckType.TempData DoWhatever(/ *異なるタイプのコレクションが渡されます* /)。ブレーク; }

flagMask >> = 1; //フラグ値を1ビット右にビットシフトします}


5


https://msdn.microsoft.com/en-us/library/system.enum.hasflag(v=vs.110).aspx[HasFlag]を使用するだけです。
if(theCheckType.HasFlag(CheckType.Form))DoSomething(...); if(theCheckType.HasFlag(CheckType.QueryString))DoSomethingElse(...); if(theCheckType.HasFlag(CheckType.TempData))DoWhatever(...);


4


あなたが感じるような「+辞書」はどうですか

dict.Add(CheckType.Form, DoSomething);
dict.Add(CheckType.TempDate, DoSomethingElse);
...

あなたの価値の分解

flags = Enum.GetValues(typeof(CheckType)).Where(e => (value & (CheckType)e) == (CheckType)e).Cast();

その後

foreach (var flag in flags)
{
   if (dict.ContainsKey(flag)) dict[flag]();
}

(未テストコード)


3


C#7では、このように書くことができます。

public void Run(CheckType checkType){switch(checkType){case型はCheckType.Form ==(typeの場合)

CheckType.QueryString ==(typeの場合はcase var型

CheckType.TempData ==(typeの場合はcase var型


1


編集内容と実際のコードに基づいて、 `+ IsValidForRequest +`メソッドを次のように更新します。

public sealed override bool IsValidForRequest
    (ControllerContext cc, MethodInfo mi)
{
    _ControllerContext = cc;

    var map = new Dictionary>
        {
            { CheckType.Form, () => CheckForm(cc.HttpContext.Request.Form) },
            { CheckType.Parameter,
                () => CheckParameter(cc.HttpContext.Request.Params) },
            { CheckType.TempData, () => CheckTempData(cc.Controller.TempData) },
            { CheckType.RouteData, () => CheckRouteData(cc.RouteData.Values) }
        };

    foreach (var item in map)
    {
        if ((item.Key & _CheckType) == item.Key)
        {
            if (item.Value())
            {
                return true;
            }
        }
    }
    return false;
}


0


C#7で可能になるはずです

switch(t1){case var tのときt.HasFlag(TST.M1):{break;} t.HasFlag(TST.M2):{break;}の場合は、var tとなります。 }


-1


最も簡単な方法は、 `+ ORed +`列挙型を実行することです。この場合、次のことができます。

[Flags()]public enum CheckType
{
    Form = 1,
    QueryString = 2,
    TempData = 4,
    FormQueryString = Form | QueryString,
    QueryStringTempData = QueryString | TempData,
    All = FormQueryString | TempData
}

`+ enum `のセットアップが完了したら、 ` switch +`ステートメントを簡単に実行できます。

たとえば、次のように設定しているとします。

var chkType = CheckType.Form | CheckType.QueryString;

次のように、次の `+ switch +`ステートメントを使用できます。

switch(chkType){
 case CheckType.Form:
   // Have Form
 break;
 case CheckType.QueryString:
   // Have QueryString
 break;
 case CheckType.TempData:
  // Have TempData
 break;
 case CheckType.FormQueryString:
  // Have both Form and QueryString
 break;
 case CheckType.QueryStringTempData:
  // Have both QueryString and TempData
 break;
 case CheckType.All:
  // All bit options are set
 break;
}

よりクリーンで、 `+ HasFlag `で ` if +`ステートメントを使用する必要はありません。 好きなように組み合わせて、switchステートメントを読みやすくすることができます。

`+ enums `を分解することをお勧めします。同じ ` enum `に異なるものを混ぜていないかどうかを確認してください。 複数の ` enums +`を設定して、ケースの数を減らすことができます。