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:
Suspended
and Revoked
are unique states that can, but don't necessarily lead to a restore.Restored
should only be possible if the user has also been Suspended
or Revoked
(or both). It's important to track specifically which event was the precursor to the restore.Suspended
and Revoked
(and Restored
)Also, I'm trying to stick to suggestions made in MSDN's Designing Flags Enumerations. In particular:
SuspendedAndRestored
and RevokedAndRestored
will both be common.Restored
is not valid unless at least one of Suspended
and Revoked
is set.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 Restored
as 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 Restored
as internal 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 Restored
as 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.
C does not have the notion of private .
Private Variables: static another use for the static keyword is to ensure that code outside this file cannot modify variables that are globally declared inside this file. If declare.c had declared farvar as: static int farvar; then the extern int farvar statement in use.c would cause an error.
In general, private variables are those variables that can be visible and accessible only within the class they belong to and not outside the class or any other class. These variables are used to access the values whenever the program runs that is used to keep the data hidden from other classes.
Class variables that are declared as private can not be referred to from other classes, they are only visible within their own class. It is considered better programming practice to use private rather than public class variables, and you should aim to do this in the remainder of the course.
Why do you want to use Flags
specifically? Is this not exactly what you are after?
public enum DriversLicenseStatus
{
None = 0,
Suspended,
Revoked,
SuspendedAndRestored,
RevokedAndRestored,
}
It will certainly be easy to make sure that only "valid" transitions are made from within the property setters of the DriversLicenseStatus
properties.
If for some reason you definitely want to use Flags
internally, then you can define a separate private enum DriversLicenseStatusFlags
and convert from that to only expose DriversLicenseStatus
values in your public interface.
Another option which could be worth considering is splitting the enum into two values:
bool IsActive;
enum InactiveReason {
None = 0,
Suspended,
Revoked,
}
The "AndRestored" cases would be those with IsActive == true
and InactiveReason != InactiveReason.None
.
I get the distinct impression that you are over-engineering here. :)
Option 3 seems as good an idea as anything to me. Bear in mind that .NET enums will not throw exceptions when they are set to undefined values, so there is nothing preventing your users from saying:
PrintDriversLicenseStatus(42);
... where PrintDriversLicenseStatus
takes a DriversLicenseFlags
as its argument.
So you'll need to have each method check its inputs anyway to make sure they're a defined value.
One other option for your consideration: Create a special internal enum class, and cast arguments to it for internal use:
[Flags]
public enum DriversLicenseFlagsInternal
{
None = 0,
Suspended = 1 << 1,
Revoked = 1 << 2,
Restored = 1 << 3,
SuspendedAndRestored = Suspended | Restored,
RevokedAndRestored = Revoked | Restored,
}
[Flags]
internal enum DriversLicenseFlags
{
None = DriversLicenseFlagsInternal.None,
Suspended = DriversLicenseFlagsInternal.Suspended,
Revoked = DriversLicenseFlagsInternal.Revoked,
SuspendedAndRestored = DriversLicenseFlagsInternal.SuspendedAndRestored,
RevokedAndRestored = DriversLicenseFlagsInternal.RevokedAndRestored,
}
public void DoSomething(DriversLicenseFlags arg)
{
var argAsInternal = (DriversLicenseFlagsInternal) arg;
// or var argAsInternal = Util.CheckDefinedDriversLicense(arg);
}
Not sure if this is any better, but it may feel less hacky.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With