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
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)
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.
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
}
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;
}
}
}
}
}
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;
}
Just use HasFlag
if(theCheckType.HasFlag(CheckType.Form)) DoSomething(...);
if(theCheckType.HasFlag(CheckType.QueryString)) DoSomethingElse(...);
if(theCheckType.HasFlag(CheckType.TempData)) DoWhatever(...);