56

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

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

問題は、次の列挙型がある場合

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

このようなスイッチを使いたい

switch(theCheckType)
{
   case CheckType.Form:
       DoSomething(/*Some type of collection is passed */);
       break;

   case CheckType.QueryString:
       DoSomethingElse(/*Some other type of collection is passed */);
       break;

   case CheckType.TempData
       DoWhatever(/*Some different type of collection is passed */);
       break;
}

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

私が見ることができる唯一の解決策は、列挙値の可能なすべての組み合わせのケースを作成することですか?

何かのようなもの

    case CheckType.Form | CheckType.TempData:
        DoSomething(/*Some type of collection is passed */);
        DoWhatever(/*Some different type of collection is passed */);
        break;

    case CheckType.Form | CheckType.TempData | CheckType.QueryString:
        DoSomething(/*Some type of collection is passed */);
        DoSomethingElse(/*Some other type of collection is passed */);
        break;

... and so on...

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

現在、代わりにお互いの直後に 3 つの If 条件があります

何かのようなもの

if ((_CheckType & CheckType.Form) != 0)
{
    DoSomething(/*Some type of collection is passed */);
}

if ((_CheckType & CheckType.TempData) != 0)
{
    DoWhatever(/*Some type of collection is passed */);
}

....

しかし、それはまた、20個の値を持つ列挙型がある場合、スイッチを使用するときのように必要な「ケース」/にのみ「ジャンプ」するのではなく、毎回20個のIf条件を通過する必要があることも意味します。

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

宣言された値をループしてからスイッチを使用する可能性を考えましたが、宣言された各値に対してのみスイッチをヒットしますが、それがどのように機能するかはわかりません。多くの場合と比較して)?

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

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


アップデート:

十分な説明ができていないことがわかりました。私の例は単純です(私のシナリオを単純化しようとしました)。

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

メソッドでこのようなことを宣言することでそれを行います

[ActionSelectorKeyCondition(CheckType.Form | CheckType.TempData, "SomeKey")]
public ActionResult Index()
{
    return View();
} 

これは、Form または TempData がメソッドを使用できるように指定されたキーを持っているかどうかを確認する必要があることを意味します。

呼び出すメソッド (前の例では doSomething()、doSomethingElse()、および doWhatever()) は、実際には戻り値として bool を持ち、パラメーター (使用できるインターフェイスを共有しない異なるコレクション) で呼び出されます。使用 - 以下のリンクにあるサンプル コードを参照してください)。

うまくいけば、私が何をしているのかをよりよく理解するために、私が実際に行っていることの簡単な例をペーストビンに貼り付けました - ここで見つけることができますhttp://pastebin.com/m478cc2b8

4

9 に答える 9

55

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

class Program
{
    [Flags]
    public enum CheckType
    {
        Form = 1,
        QueryString = 2,
        TempData = 4,
    }

    private static bool DoSomething(IEnumerable cln)
    {
        Console.WriteLine("DoSomething");
        return true;
    }

    private static bool DoSomethingElse(IEnumerable cln)
    {
        Console.WriteLine("DoSomethingElse");
        return true;
    }

    private static bool DoWhatever(IEnumerable cln)
    {
        Console.WriteLine("DoWhatever");
        return true;
    }

    static void Main(string[] args)
    {
        var theCheckType = CheckType.QueryString | CheckType.TempData;
        var checkTypeValues = Enum.GetValues(typeof(CheckType));
        foreach (CheckType value in checkTypeValues)
        {
            if ((theCheckType & value) == value)
            {
                switch (value)
                {
                    case CheckType.Form:
                        DoSomething(null);
                        break;
                    case CheckType.QueryString:
                        DoSomethingElse(null);
                        break;
                    case CheckType.TempData:
                        DoWhatever(null);
                        break;
                }
            }
        }
    }
}
于 2009-07-06T23:38:37.023 に答える
6

C# 7 では、次のように記述できるようになりました。

public void Run(CheckType checkType)
{
    switch (checkType)
    {
        case var type when CheckType.Form == (type & CheckType.Form):
            DoSomething(/*Some type of collection is passed */);
            break;

        case var type when CheckType.QueryString == (type & CheckType.QueryString):
            DoSomethingElse(/*Some other type of collection is passed */);
            break;

        case var type when CheckType.TempData == (type & CheckType.TempData):
            DoWhatever(/*Some different type of collection is passed */);
            break;
    }
}
于 2018-06-06T11:49:46.530 に答える
1

あなたの編集と実際のコードに基づいて、おそらくIsValidForRequestメソッドを次のように更新します。

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

    var map = new Dictionary<CheckType, Func<bool>>
        {
            { 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;
}
于 2009-06-24T22:45:39.247 に答える
-2

最も簡単な方法は、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;
}

ifはるかにクリーンで、ステートメントを with で使用する必要はありませんHasFlag。任意の組み合わせを作成して、switch ステートメントを読みやすくすることができます。

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

于 2017-11-04T20:30:04.260 に答える