views:

172

answers:

2

I have the following code (example), and I'm really not comfortable with so many 'if' checks:

public enum Flags 
{
    p1 = 0x01,  // 0001
    p2 = 0x02,  // 0010  
    p3 = 0x04,  // 0100
    p4 = 0x08   // 1000
};      

public static void MyMethod (Flags flag)
{
    if ((flag & Flags.p1) == Flags.p1)
        DoSomething();

    if ((flag & Flags.p2) == Flags.p2)
        DosomethingElse();

    if ((flag & Flags.p3) == Flags.p3)
        DosomethingElseAgain();

    if ((flag & Flags.p4) == Flags.p4)
        DosomethingElseAgainAndAgain();
}

MyMethod(Flags.p1 | Flags.p3);

Is there some way, that i could use an 'switch' statement. Maybe if I convert them to strings, or use arrays?

+6  A: 

Something like this?

public static void MyMethod(Flags flag)
{
    // Define action-lookup
    var actionsByFlag = new Dictionary<Flags, Action>
    {
        { Flags.p1, DoSomething},
        { Flags.p2, DosomethingElse},
        { Flags.p3, DosomethingElseAgain},
        { Flags.p4, DosomethingElseAgainAndAgain},
    };

    // Find applicable actions
    var actions = actionsByFlag.Where(kvp => (flag & kvp.Key) == kvp.Key)
                               .Select(kvp => kvp.Value);

    //Execute applicable actions
    foreach (var action in actions)
       action();
}

EDIT: If the order of actions are important, an OrderBy clause may be required.

Ani
In C# 4.0 you can use `dict.Where(kv => flag.HasFlag(kv.Key))`
Callum Rogers
I like that @Ani, Dictionary and LINQ. Thanks to @Gabe and @Callum Rogers for mentioning new C# 4.0 feature.
kofucii
Good answer, but define action-lookup *outside* the method.
Caspar Kleijne
Caspar: The action lookup may require state that's only available inside that method. If not, though, it should be defined outside the method.
Gabe
@Callum Rogers: Thanks, that's a good point.
Ani
This is nice, but, to be honest, I think this is harder to read than the simple series of tests and methods. This version requires that the maintaining developer understand a number of intermediate-level concepts and (of lesser concern), it takes considerably longer to execute. As long as the logic for each flag case is delegated to helper methods, I think the initial implementation is actually quite clean.
Dan Bryant
@Dan Bryant: I agree with you; my answer actually has more code than the initial implementation. I do think the dictionary approach is more readable after you've seen the pattern once, though. I would use it if a) performance were not a concern b) there were several (many more than 4 anyway) flags.
Ani
+3  A: 

Here's a variation on Ani's answer:

public static void MyMethod(Flags flag) 
{ 
    // Define action-lookup 
    var dict = new Dictionary<Flags, Action> 
    { 
        { Flags.p1, DoSomething}, 
        { Flags.p2, DosomethingElse}, 
        { Flags.p3, DosomethingElseAgain}, 
        { Flags.p4, DosomethingElseAgainAndAgain}, 
    }; 

    // Find applicable actions 
    var actions = from value in Enum.GetValues(typeof(Flags))
                  where flag.HasFlag(value)
                  select dict[value];

    //Execute applicable actions 
    foreach (var action in actions)
       action(); 
}

The important difference here is that it iterates over the defined values in the enumeration rather than the entries in the dictionary. That way if you add a new flag to the enum without adding it to the dictionary, you will get an exception when you try to use the new flag. And it always iterates in order of the flags.

Gabe