Switch on Enum (with Flags attribute) without declaring every possible combination?

后端 未结 9 2018
忘掉有多难
忘掉有多难 2021-01-31 14:15

how do i switch on an enum which have the flags attribute set (or more precisely is used for bit operations) ?

I want to be able to hit all cases in a switch that matche

相关标签:
9条回答
  • 2021-01-31 14:39

    What about a Dictionary<CheckType,Action> that you will fill like

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

    a decomposition of your value

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

    and then

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

    (code untested)

    0 讨论(0)
  • 2021-01-31 14:44

    The easiest way is to just perform an ORed enum, in your case you could do the following :

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

    Once you have the enum setup its now easy to perform your switch statement.

    E.g, if i have set the following :

    var chkType = CheckType.Form | CheckType.QueryString;
    

    I can use the following switch statement as follows :

    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;
    }
    

    Much cleaner and you don't need to use an if statement with HasFlag. You can make any combinations you want and then make the switch statement easy to read.

    I would recommend breaking apart your enums, try see if you are not mixing different things into the same enum. You could setup multiple enums to reduce the number of cases.

    0 讨论(0)
  • 2021-01-31 14:45

    Flags enums can be treated as a simple integral type in which each individual bit corresponds to one of the flagged values. You can exploit this property to convert the bit-flagged enum value into an array of booleans, and then dispatch the methods you care about from a correlated array of delegates.

    EDIT: We could certainly make this code more compact through the use of LINQ and some helper functions, but I think it's easier to understand in the less sophisticated form. This may be case where maintainability trumps elegance.

    Here's an example:

    [Flags()]public enum CheckType
    {
      Form = 1,       
      QueryString = 2,
      TempData = 4,
    }
    
    void PerformActions( CheckType c )
    {
      // array of bits set in the parameter {c}
      bool[] actionMask = { false, false, false };
      // array of delegates to the corresponding actions we can invoke...
      Action availableActions = { DoSomething, DoSomethingElse, DoAnotherThing };
    
      // disassemble the flags into a array of booleans
      for( int i = 0; i < actionMask.Length; i++ )
        actionMask[i] = (c & (1 << i)) != 0;
    
      // for each set flag, dispatch the corresponding action method
      for( int actionIndex = 0; actionIndex < actionMask.Length; actionIndex++ )
      {
          if( actionMask[actionIndex])
              availableActions[actionIndex](); // invoke the corresponding action
      }
    }
    

    Alternatively, if the order in which you evaluate doesn't matter, here is simpler, clearer solution that works just as well. If order does matter, replace the bit-shifting operations with an array containing the flags in the order you want to evaluate them in:

    int flagMask = 1 << 31; // start with high-order bit...
    while( flagMask != 0 )   // loop terminates once all flags have been compared
    {
      // switch on only a single bit...
      switch( theCheckType & flagMask )
      {
       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;
      }
    
      flagMask >>= 1;  // bit-shift the flag value one bit to the right
    }
    
    0 讨论(0)
  • 2021-01-31 14:47

    How about this. Of course the arguments and return types of DoSomething, etc., can be anything you like.

    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;
                    }
                }
            }
        }
    }
    
    0 讨论(0)
  • 2021-01-31 14:58

    Cast it to its base type, the great thing about this is it tells you when there are duplicate values present.

    [Flags]
    public enum BuildingBlocks_Property_Reflection_Filters
    {
        None=0,
        Default=2,
        BackingField=4,
        StringAssignment=8,
        Base=16,
        External=32,
        List=64,
        Local=128,
    }
    
    switch ((int)incomingFilter)
    {
        case (int)PropFilter.Default:
            break;
        case (int)PropFilter.BackingField:
            break;
        case (int)PropFilter.StringAssignment:
            break;
        case (int)PropFilter.Base:
            break;
        case (int)PropFilter.External:
            break;
        case (int)PropFilter.List:
            break;
        case (int)PropFilter.Local:
            break;
        case (int)(PropFilter.Local | PropFilter.Default):
            break;
    
    }
    
    0 讨论(0)
  • 2021-01-31 15:01

    Just use HasFlag

    if(theCheckType.HasFlag(CheckType.Form)) DoSomething(...);
    if(theCheckType.HasFlag(CheckType.QueryString)) DoSomethingElse(...);
    if(theCheckType.HasFlag(CheckType.TempData)) DoWhatever(...);
    
    0 讨论(0)
提交回复
热议问题