I’m creating a flags enumeration in C#, similar to the following:
[Flags]
public enum DriversLicenseFlags
{
None = 0,
Suspended = 1 << 1,
Revoked = 1 << 2,
Restored = 1 << 3,
SuspendedAndRestored = Suspended | Restored,
RevokedAndRestored = Revoked | Restored,
}
A couple notes about my intentions here:
SuspendedandRevokedare unique states that can, but don’t necessarily lead to a restore.Restoredshould only be possible if the user has also beenSuspendedorRevoked(or both). It’s important to track specifically which event was the precursor to the restore.- A license can be both
SuspendedandRevoked(andRestored)
Also, I’m trying to stick to suggestions made in MSDN’s Designing Flags Enumerations. In particular:
- Consider providing special enumeration values for commonly used combinations of flags.
SuspendedAndRestoredandRevokedAndRestoredwill both be common.
- Avoid creating flags enumerations when certain combinations of values are invalid.
- This is my problem, because
Restoredis not valid unless at least one ofSuspendedandRevokedis set.
- This is my problem, because
Ideally, I’d like a value for Restored to be present in the enum for internal usage, but only available to set publicly via some valid combination. Unfortunately, internal isn’t a valid modifier for enum values.
I’ve thought of a few alternatives, but each seems to have drawbacks:
-
Keep
Restoredas a public value, note the limitations in comments and do a precondition check for invalid combinations on public APIs.This would work, and is likely the solution I will go with. However, it seems like their should be a cleaner solution.
-
Use an enhanced, java-like enum as described here and define
Restoredasinternal static.This would also work, but feels like overkill because I don’t need any of the other functionality at this point.
-
Don’t define
Restoredas a value, but reserve the value for OR’ing, and for checking the value in consuming methods. i.e.:internal const int RestoredFlag = 1 << 3; [Flags] public enum DriversLicenseFlags { None = 0, Suspended = 1 << 1, Revoked = 1 << 2, SuspendedAndRestored = Suspended | RestoredFlag, RevokedAndRestored = Revoked | RestoredFlag, }
This feels hacky me, both in how it’s defined and how it will be used internally.
Why do you want to use
Flagsspecifically? Is this not exactly what you are after?It will certainly be easy to make sure that only “valid” transitions are made from within the property setters of the
DriversLicenseStatusproperties.If for some reason you definitely want to use
Flagsinternally, then you can define a separateprivate enum DriversLicenseStatusFlagsand convert from that to only exposeDriversLicenseStatusvalues in your public interface.Another option which could be worth considering is splitting the enum into two values:
The “AndRestored” cases would be those with
IsActive == trueandInactiveReason != InactiveReason.None.I get the distinct impression that you are over-engineering here. 🙂