Reputation: 196539
We were having a debate if enums should have uninitialized values. For example. We have
public enum TimeOfDayType
{
Morning
Afternoon
Evening
}
or
public enum TimeOfDayType
{
None
Morning
Afternoon
Evening
}
I think that there shouldn't be any none but then you have to default to some valid value on initialization. But others thought there should be some indication of uniitized state by having another enum that is None or NotSet.
thoughts?
Upvotes: 9
Views: 3970
Reputation: 1012
I always set one of my enum literals to zero. This literal must not always be named "None" or "NotSet". It depends if there is a literal which acts very well as default.
I set one to zero because, enums (except nullable enums) are always initialized by the CLR in memory to zero. And if you don't define one of the literals this memory contains illegal values. Also when you use enums as flags. The Default value cannot be used to do bitwise compairisons. The result will always be zero.
When you enable FxCop it checks if you have defined a literal as default. Seems to be a "good practice" when they have a rule for that.
Upvotes: 7
Reputation: 754763
In the abscence of a "default" member, I think it's valuable to have a value representing the literal int 0.
No matter what, a given enum will be created with the literal value 0. The most straight forward case here is as a member of a struct. A C# struct will always have an empty default constructor that initalizes all fields to their default value. In the case of an enum, that will be the literal value 0. The question is how to handle it.
For me this is an issue of style: If the enum is not explicitly initialized to a value, should it be given an arbitrary valid value or a specific value indicating a lack of explicit initialization?
enum Color { Unknown, Red, Blue }
enum Color2 { Red,Blue }
struct Example<T> {
Color color;
}
static void SomeMethod() {
var v1 = new Example<Color>();
var v2 = new Example<Color2>();
}
In the case of v1, if the color field is inspected it will explicitly be labeled as an uninitialized field. In v2 the field will simple be "Red". There is no way for a programmer to detect between and explicit set to "Red" or an implicit default value to "Red".
Another case where this causes a problem is doing a switch statement against an enum value. Lets slighly alter the definition of Color2.
enum Color2 { Red = 1, Blue = 2 }
static void SomeOtherMethod(p1 as Example<Color2>) {
switch ( p1.color ) {
case Color.Red: {}
case Color.Blue: {}
default: {throw new Exception("What happened?"); }
}
}
The switch handles every explicit value in the enum. Yet this code will fail for the default constructor of Example<Color2> and there is no way to supress this constructor.
This brings up a slighly more important rule: Have an explicit enum value for the literal value 0.
Upvotes: 5
Reputation: 3715
A nullable enum was proposed as a solution in some of the previous answers. But a nullable enum has the disadvantage that it makes clients check for a null value every time they use the enum. On the contrary, if you have a default value of "None", you have the option to use a switch for the meaningful values and just ignore "None", without having to worry that the enum variable could be null.
Anyway, I think having a default value of "None" or making the enum nullable makes sense only if the enum is used as an argument in a default constructor for some class. And you have to ask yourself - shouldn't the objects of that class have some meaningful default value? Using your example with the TimeOfDayType enum - if you initialize an object with TimeOfDayType.None, you can't use it anyway before you change the value to Morning, Afternoon or Evening. So couldn't you say that the default is Morning instead of None? Or - which is even better - couldn't you create your objects after you already know which enum value they need? I think that if the issue is correctly tackled with at the early design stages, you shouldn't need a special default value for your enums at all.
Of course, all of the above is a generalization. Maybe it can't be applied to your particular scenario, so if you give some details about it, we could discuss the issue more thoroughly.
Upvotes: 5
Reputation: 17793
Just adding to Franks answer, one of the only times I would opt for a 'None' item in an enum over nullable is when the enum is being used as flags. The 'None' item would be id of 0.
Upvotes: 3
Reputation: 70993
Speaking of nullable types - I think they can be used to solve the problem of forcing/not forcing the initialization of an enum. Say we have
enum Color { Red, Blue }
And let's say you have a function:
void Draw(Color c);
That function says that it requires a valid Color
. However, we could also have this function:
void Draw(Color? c);
That says that the function can handle not being passed a color (null
would be passed to indicate "don't care").
Well, it's one alternative to None
members.
Upvotes: 13
Reputation: 279255
Depends how the type is used. It's often easier for users of the type not to have an "undefined" value, because you don't have to special-case one value. But if you need one (because values sometimes need to be in a state which is otherwise not any of the enumerated values) then you need one. You usually don't save any special-case code by using two enums instead of one.
It's a bit like asking whether you should use nullable types.
Upvotes: 1