8
\$\begingroup\$

I have this code, but it looks a bit verbose:

enum MonitoringMode
{
    Seek,
    Destroy
}
void ToggleMonitoringMode()
{
    if (_monitoringMode == MonitoringMode.Seek)
        _monitoringMode = MonitoringMode.Destroy;
    else
    if (_monitoringMode == MonitoringMode.Destroy)
        _monitoringMode = MonitoringMode.Seek;
}

There are some well known idioms to toggle between two values, like:

bitwiseBoolean ^= bitwiseBoolean; // bit toggle
boolean = !boolean;               // boolean toggle
oneOrZero = 1 - oneOrZero;        // numeric toggle

Is there a similar, less verbose way to get the same result? I am not sure using the int value of enums would be safe or even "elegant" in C#.

\$\endgroup\$
5
  • 4
    \$\begingroup\$ If your enum only has two values, you don't have an enum, you have a bool. \$\endgroup\$ – Kevin Aug 26 '15 at 21:09
  • \$\begingroup\$ @Kevin technicaly speaking it's true but to make the meaning of true/false more verbose I also prefer to use enums in many situations. \$\endgroup\$ – t3chb0t Aug 27 '15 at 19:32
  • \$\begingroup\$ then you are making toggling a lot harder than it has to be. bool InDestroyMode =true; InDestroyMode = !InDestroyMode is a lot simpler than the accepted answer. \$\endgroup\$ – Kevin Aug 27 '15 at 20:01
  • 1
    \$\begingroup\$ @Kevin pasting my comment on moarboilerplate's answer: I thought about using boolean, but boolean has an "apple vs non-apple" semantics, while I prefer (or actually, the application requires) an "apple vs orange (vs not-yet-considered fruit)" semantics. \$\endgroup\$ – heltonbiker Aug 27 '15 at 20:30
  • \$\begingroup\$ Yes, if you know there are going to be further options later, then boolean is not the way to go \$\endgroup\$ – Kevin Aug 27 '15 at 20:42
11
\$\begingroup\$

Would there ever be a need to add more values to the MonitoringMode enum?

enum MonitoringMode
{
    Seek,
    Destroy,
    Something,
    SomethingElse
}

In that case, you're not "toggling" - you're mapping. And there's a data structure for that:

private static readonly IDictionary ModeMap = new Dictionary<MonitoringMode,MonitoringMode>
{
    { MonitoringMode.Seek, MonitoringMode.Destroy },
    { MonitoringMode.Destroy, MonitoringMode.Seek },
    // ...
};

Then you could switch from one value to the next simply by using that map:

void ToggleMonitoringMode()
{
    _monitoringMode = ModeMap[_monitoringMode];
}

If there's not going to be a need to ever add more values, then I'd question the use of an enum type here, because you're really toggling between true and false states of some _isSeeking Boolean, which you already know how to toggle.

\$\endgroup\$
10
  • \$\begingroup\$ You're right. I must say I have two modes NOW but they are not intrinsically binary (that is, I can see a lot of future reasons demanding additional modes). I'll wait a little bit before accepting, but this is a very interesting solution indeed! Thanks for now! \$\endgroup\$ – heltonbiker Aug 26 '15 at 18:42
  • 3
    \$\begingroup\$ Picking on Mr. Mug a bit here, mapping based on a dictionary turns all of your rules that could be expressed statically in code and unit tested individually into items that are evaluated at runtime, which could be an issue. Especially if diagnosing problems requires peeking into said collection using a debugger \$\endgroup\$ – moarboilerplate Aug 26 '15 at 20:56
  • \$\begingroup\$ @moarboilerplate fair point. How about making ModeMap public then, and have unit tests that validate the mappings? ...or better - constructor-injected as IDictionary<MonitoringMode,MonitoringMode> mappingRules? \$\endgroup\$ – Mathieu Guindon Aug 26 '15 at 21:00
  • \$\begingroup\$ That would work provided the values in your dictionary are all value types or expressions. But it all hinges on the question of why a mapping rule should be stored as a representation of itself and not explicitly coded instructions. If the answer is "developer convenience" that may be problematic. \$\endgroup\$ – moarboilerplate Aug 26 '15 at 21:13
  • 2
    \$\begingroup\$ You'd think so, but the things I've seen, man. \$\endgroup\$ – moarboilerplate Aug 26 '15 at 21:24
2
\$\begingroup\$

If you are into bit-twiddling, you can have your cake and eat it too with the [Flags] attribute. However, I would only use this when you want to represent combinations of more than one value, you want to execute conditionals based on these values, and/or your zeroth value has significant meaning (but I'd still use a bool for simplicity over a 2-item enum).

\$\endgroup\$
2
  • 1
    \$\begingroup\$ That's a good option (the Flags attribute). I thought about using boolean, but boolean has a "apple vs non-apple" semantics, while I prefer (or actually, the application deserves) an "apple vs orange" semantics. \$\endgroup\$ – heltonbiker Aug 26 '15 at 22:00
  • 1
    \$\begingroup\$ I would really only use the flags if your values are additive qualities. So apple would not be Apple, it would be GrowsOnTree | IsRed (terrible example, I've never thought so hard about how to classify an apple). Maybe what you're really after is the concept of a discriminated union? \$\endgroup\$ – moarboilerplate Aug 26 '15 at 22:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.