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#.
2 Answers 2
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.
-
\$\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– heltonbiker2015年08月26日 18:42:40 +00:00Commented Aug 26, 2015 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– moarboilerplate2015年08月26日 20:56:07 +00:00Commented Aug 26, 2015 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 asIDictionary<MonitoringMode,MonitoringMode> mappingRules
? \$\endgroup\$Mathieu Guindon– Mathieu Guindon2015年08月26日 21:00:54 +00:00Commented Aug 26, 2015 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– moarboilerplate2015年08月26日 21:13:17 +00:00Commented Aug 26, 2015 at 21:13
-
2\$\begingroup\$ You'd think so, but the things I've seen, man. \$\endgroup\$moarboilerplate– moarboilerplate2015年08月26日 21:24:08 +00:00Commented Aug 26, 2015 at 21:24
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).
-
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– heltonbiker2015年08月26日 22:00:35 +00:00Commented Aug 26, 2015 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 beGrowsOnTree | 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– moarboilerplate2015年08月26日 22:08:58 +00:00Commented Aug 26, 2015 at 22:08
bool InDestroyMode =true;
InDestroyMode = !InDestroyMode
is a lot simpler than the accepted answer. \$\endgroup\$