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.