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

C#EnumsSwitch StatementFlagsBit

C# Problem Overview


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 matches the values declared.

The problem is that if i have the following enum

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

and I want to use a switch like this

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

If "theCheckType" is set to both CheckType.Form | CheckType.TempData I want it to hit both case's. Obviously it wont hit both in my example because of the break, but other than that it also fails because CheckType.Form is not equal to CheckType.Form | CheckType.TempData

The only solution then as I can see it is to make a case for every possible combination of the enum values ?

Something like

    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...

But that really isnt very desired (as it will quickly grow very big)

Right now i have 3 If conditions right after eachother instead

Something like

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

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

....

But that also means that if i have an enum with 20 values it have to go through 20 If conditions every single time instead of "jumping" to only the needed "case"/'s as when using a switch.

Is there some magic solution to solve this problem?

I have thought of the possibility to loop through the declared values and then use the switch, then it would only hit the switch for each value declared, but I don't know how it will work and if it performance vice is a good idea (compared to a lot of if's) ?

Is there an easy way to loop through all the enum values declared ?

I can only come up with using ToString() and splitting by "," and then loop through the array and parse every single string.


UPDATE:

I see that i haven't done a good enough job explaining. My example is to simple (tried to simplify my scenario).

I use it for a ActionMethodSelectorAttribute in Asp.net MVC to determine if a method should be available when resolving the url/route.

I do it by declaring something like this on the method

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

That would mean that it should check if the Form or TempData have a key as specified for the method to be available.

The methods it will be calling (doSomething(), doSomethingElse() and doWhatever() in my previous example) will actually have bool as return value and will be called with a parameter (different collections that doesn't share a interface that can be used - see my example code in the link below etc).

To hopefully give a better idea of what i am doing i have pasted a simple example of what i am actually doing on pastebin - it can be found here http://pastebin.com/m478cc2b8

C# Solutions


Solution 1 - C#

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

Solution 2 - C#

Just use HasFlag

if(theCheckType.HasFlag(CheckType.Form)) DoSomething(...);
if(theCheckType.HasFlag(CheckType.QueryString)) DoSomethingElse(...);
if(theCheckType.HasFlag(CheckType.TempData)) DoWhatever(...);

Solution 3 - C#

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
}

Solution 4 - C#

Should be possible in C# 7

switch (t1)
    {
        case var t when t.HasFlag(TST.M1):
            {
                break;
            }
        case var t when t.HasFlag(TST.M2):
            {
                break;
            }

Solution 5 - C#

With C# 7 you can now write something like this:

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

Solution 6 - C#

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)

Solution 7 - C#

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

Solution 8 - C#

Based on your edit and your real-life code, I'd probably update the IsValidForRequest method to look something like this:

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

Solution 9 - C#

I know this has already been solved, and there are several good answers here, but I really was wanting the same thing that the OP was asking for.

> Is there an easy way to loop through all the enum values declared ?

Of course, Jamie's accepted solution does it nicely, and there are a few other interesting answers, but I really wanted to get something a little more general and natural to use, so here's what I came up with:

public static TFlags[] Split<TFlags>(this TFlags flags) // , bool keepUndefined)
    where TFlags : Enum
{
    ulong valueToSplit = Convert.ToUInt64(flags);
    TFlags[] definedFlags = (TFlags[])Enum.GetValues(typeof(TFlags));
    List<TFlags> resultList = new List<TFlags>();

    if (valueToSplit == 0)
    {
        TFlags flagItem = 
            Array.Find(definedFlags, flag => Convert.ToUInt64(flag) == 0x00);
        resultList.Add(flagItem);
    }

    ulong checkBitValue = 1L;
    while (valueToSplit != 0)
    {
        ulong checkValue = checkBitValue & valueToSplit;
        if (checkValue != 0)
        {
            valueToSplit &= ~checkValue;

            TFlags flagItem =
                Array.Find(definedFlags, flag => Convert.ToUInt64(flag) == checkValue);

            // undefined flag, need a way to convert integer to TFlags
            if (Convert.ToUInt64(flagItem) != checkValue)
            {
                //if (keepUndefined)
                //    resultList.Add(checkValue);                        
                continue;
            }

            resultList.Add(flagItem);
        }

        checkBitValue <<= 1;
    }

    return resultList.ToArray();
}

(This code has been marginally tested and is working well for me so far.)

Issues converting between TFlags and integer types

I never could find a way to force a cast of an arbitrary integer value, even checking for and matching the underlying type. It always gives me an error converting integer to TFlags.

I'm assuming it's something to do with it being a generic type parameter instead of the real type. I feel like there's probably something obvious and I'll be kicking myself when I find it.

A possible solution is to have the caller supply a function that will cast it for you; but that seemed to go against trying to keep it generic and usable. You could put it in as an default null parameter and if it's passed in then that indicates you want to keep the undefined flags.

Fortunately it works out okay the other way around, I think you can cast from pretty much any integer type to an Enum, otherwise this would have been much harder. That way I was able to just use ulong and not worry about having to get the underlying type and doing some big switch statement to get a properly-size integer.

Usage

So, the idea is just that this way you do a Split() on the flags value you need to take action on, and it gives you an array of all the defined ones so you can just loop and do a switch as usual. LBushkin mentioned ordering, there's no attempt to do that here other than that these are in ascending order by flag value.

I actually think the original code in the post wasn't so bad notionally. It seemed like there was an aversion to doing something like in the accepted answer where you loop over all the possible flags and switch. But, in most circumstances, a loop and a switch should be pretty fast for the flags that aren't used, so unless this is running in a tight loop it's probably fine for most cases.

But I did like the idea of making it where you can do something more natural.

public DoTheChecks(CheckType typesToCheck)
{
    CheckType[] allCheckTypes = typesToCheck.Split();

    foreach (CheckType singleCheck in allCheckTypes)
        switch (singleCheck)
        {
            case CheckType.Form:
                CheckTheForms();
                break;

And so forth.

Final Notes

LBushkin's post, which also is going through the bitmap to figure out what flags have been set, has a comment asking about accounting for a None = 0 flag. I added in a check so that if the flag comes in as zero, we check for a default flag and add it if it exists.

This code does not check for the Flags() attribute on the Enum, so it's possible to pass in a non-flags enum which likely will not produce the expected results. Probably it would be worth checking for that and throwing an exception. I don't see any reason to implement something like this for non-flag enums, but the language doesn't really give much way to deal with it that I know of. The worst thing that should happen if someone does is they will get garbage back.

Other than being able to set an arbitrary undefined flag value, this does pretty much everything I wanted. It took me a really long time to figure out how to do everything, though. You can tell they never meant for you to work with Enums like this.

Solution 10 - C#

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMartinFView Question on Stackoverflow
Solution 1 - C#Jamie IdeView Answer on Stackoverflow
Solution 2 - C#Stijn Van AntwerpenView Answer on Stackoverflow
Solution 3 - C#LBushkinView Answer on Stackoverflow
Solution 4 - C#justromagodView Answer on Stackoverflow
Solution 5 - C#Alex SanséauView Answer on Stackoverflow
Solution 6 - C#RauhotzView Answer on Stackoverflow
Solution 7 - C#MatthewOrionosView Answer on Stackoverflow
Solution 8 - C#LukeHView Answer on Stackoverflow
Solution 9 - C#shelleybutterflyView Answer on Stackoverflow
Solution 10 - C#JosephView Answer on Stackoverflow