Why the default enum value is 0 and not the minimum one? - c#

What's the point of having '0' as a default value for enum in C#? If I declare enumeration that starts with a different number:
enum Color
{
Blue = 1,
Green,
Red,
}
then var color = default(Color) - will return me '0'. I expected to see the minimum value instead. This behavior may cause problems if each member of the enumeration corresponds to some specific number and '0' is not a valid value.

Default value for all value types (including enum) is bitwise 0. As result it means that 0 is always possible value for enum even if it is not explicitly defined.
Here is the specification: Default values table
EDIT: for more details check MSDN for enumeration types - enum
enum is type which is special in a way the it sort-of derives from other value type (which normally not possible), but behaves as value type of its backing type. An enum can use only some integral values as backing type.
Note: as #archil points out enum value may contain any value of backing type, irrespective of list of constants enumerated in enum itself. For enums marked with "FlagsAttribute" this behavior is normally expected, but for normal enums it may not be intuitive.

We can only conjecture about why an aspect of the .NET framework was designed a certain way. For the most straightforward explanation, I'd like to highlight this remark from the MSDN documentation:
An enumeration is a set of named constants whose underlying type is
any integral type except Char. If no underlying type is explicitly
declared, Int32 is used.
Note that a .NET enumeration is essentially an extension of an integral type. The default value for integral types is 0, so it's reasonable (if somewhat inconvenient in the cases you've illustrated) for enumerations to inherit that behaviour.

There always is possibility for enum to have non-existent value. That is why Enum.IsDefined Method exists.
The default value of an enum E is the value produced by the expression
(E)0.

As has been stated in multiple answers so far, the "default" value for any fixed-size data structure is 0. The size of the structures memory is set to zero and that is considered "default". Now, if you want to define your own "default" value for an enum, you have multiple options. The easiest would be to write your own function to give you a "minimum valid enum"
private E GetDefaultEnum<E>()
{
return (E)(Enum.GetValues(typeof(E)).Cast<E>().Min<E>());
}
Usage:
enum Color
{
Blue = 1,
Green,
Red,
}
Color defaultColor = GetDefaultEnum<Color>();
MessageBox.Show(defaultColor.ToString()); // "Blue"
You can obviously alter how you determine a "default" value, but this way seems best suited to your needs.

Why is 0 the default enum value? Ease of runtime implementation. The default of any value type is bitwise 0, and presumably a null reference is represented by bitwise 0. Thus to initially construct an object with its default values, we only need to know its size; the runtime doesn't need to know or process anything about the object's structure. Similarly, the pre-defined value-type constructor can merely fill a memory range with zeroes.
Like it or not, that's how it is. What we need to do in response is when designing an enum, whatever name is a suitable default, give it the value 0. If there is no suitable default, then your methods accepting such an enum as a parameter might check that it's properly set, e.g.
void ProcessColor(Color c) {
if (c == 0)
throw new ArgumentException("Color is not set", "c");
//...
}

The point is probabbly is in having less positive integer possible value.
Why less positive?
To be able to treat enum with bit-shift operation correctly.
I'm naturally talking about default value, that can be changed by developer.

I am not sure why but...
Here is the doc about C# enum: http://msdn.microsoft.com/en-us/library/sbbt4032.aspx
Enumerators can use initializers to override the default values, as shown in the following example.
enum Days {Sat=1, Sun, Mon, Tue, Wed, Thu, Fri};
In this enumeration, the sequence of elements is forced to start from 1 instead of 0. However, including a constant that has the value of 0 is recommended. For more information, see Enumeration Types (C# Programming Guide).
They recommend you always include a placeholder enum value which corresponds to the value 0 otherwise you may run into problems. You could name this enum value something like Undefined or Default or something like that.
As I mentioned in my comment to your question though, my recomendation would be to not use values for your enums at all unless you have a very good reason for doing so. If you need to, follow the MSDN Programming Guide for Enumeration Types

enum is int (by default). Enums are human-readable ints for our source code, but when your program gets compiled, there is no enum, only ints. The default value for int is 0.
This code:
public enum test { One, Two, Three }
var x = test.One;
var y = 0;
Becomes this in IL:
IL_0001: ldc.i4.0
IL_0002: stloc.0
IL_0003: ldc.i4.0
IL_0004: stloc.1
So, how could an int have a default value of 1 (as you ask) in some cases, but not others?

Related

Conversion of numeric strings to enum in C#

Recently I've discovered that any string that contains only numeric characters can be converted to enum in C#. For example, imagine there is an enum defined as follows:
public enum TestEnum
{
One = 1,
Two = 2,
Three = 3
};
I can perform a conversion of some random numeric string to TestEnum.
TestEnum testEnum = (TestEnum)Enum.Parse(typeof(TestEnum), "4");
Console.WriteLine(testEnum);
The value '4' of course does not get mapped to one of defined TestEnum values and the output would be just 4, however there would be no error, so this conversion is legal.
On the other hand, if I try to check whether this value defined in TestEnum:
Console.WriteLine(Enum.IsDefined(typeof(TestEnum), "4"));
I would receive False in the output.
This seems a little strange to me, taking into account that the following conversion of non-numeric string, e.g.
(TestEnum)Enum.Parse(typeof(TestEnum), "Test")
will throw System.ArgumentException.
I am confused with such behavior. Was it intentionally designed this way or is this just a coincidence?
Was it intentionally designed this way or is this just a coincidence?
I'm not sure I understand your question. The documentation seems completely clear to me:
Converts the string representation of the name or numeric value of one or more enumerated constants to an equivalent enumerated object.
(Emphasis mine)
It also says:
If value is the string representation of an integer that does not represent an underlying value of the enumType enumeration, the method returns an enumeration member whose underlying value is value converted to an integral type. If this behavior is undesirable, call the IsDefined method to ensure that a particular string representation of an integer is actually a member of enumType
Clearly this is intentional behavior, and not just coincidental.
Note that you can always cast any value of the enum's underlying type (int in this case), to the enum type itself. The enum type feature does not enforce values of the enum to correspond to named value. So the parsing behavior is entirely consistent with the compile-time behavior of enum types.
I suppose one might debate whether the enum type should allow unnamed values to be used. But, given that one of the features of enum types is to allow for flag-based enums, whether or not they have the [Flags] attribute, and given that it would be inconvenient (to say the least) to have to name every single combination of every single flag one defines in an enum type, it seems reasonable that they would go ahead and allow unnamed values for all types of enum types.

Can an enum be null in C#

Just wondering if an enum can be null in C#?
Specifically I'm interested in the HttpStatusCode implementation of enum in C#.
What will happen if I will not assign a value to a variable of the HttpStatusCode
type? What will happen if I will try to assign a value that is not expected?
From MSDN:
Every enumeration type has an underlying type, which can be any integral type except char. The default underlying type of enumeration elements is int. To declare an enum of another integral type, such as byte, use a colon after the identifier followed by the type, as shown in the following example.
C#
enum Day : byte {Sat=1, Sun, Mon, Tue, Wed, Thu, Fri};
The approved types for an enum are byte, sbyte, short, ushort, int, uint, long, or ulong.
Since these are only value types, the enum itself cannot be null.
Of course you can wrap it in a Nullable, which allows value types to behave "nullable", but technically, Nullable<T> is a generic struct type (non-nullable) and not an enum itself, it's just a wrapper as by definition:
public struct Nullable<T> where T : struct
You might wonder: how can a struct be null? See this answer for an explanation:
Nullable<bool> b = new Nullable<bool>();
Basically, it's never null. It a compiler trick to guarantee that the values like e.g.: HasValue are always available.
HttpStatusCodes Enum
In your particular question about HttpStatusCodes.
What is actually happening is that the "code reader friendly" enum such as StatusCodes.400NotFound is just a representation of an integer value of 400. You can just manually use an integer value as the argument if you like, but then someone else reading your code may not understand the HTTP status code.
For example, if I just wrote in my code the status code422, is it easy to read / understand? Probably not a good idea. Someone reading your code will have a better chance if you use StatusCode.422UnprocessableEntity.
What are the valid HTTP status codes?
If you are sending back an HTTP response, you can designate any of the integer values listed here... https://en.wikipedia.org/wiki/List_of_HTTP_status_codes
Unassigned or default behavior(s)?
Without knowing what method or what server you are using, your question about "what happens if it is unassigned". The usual answer is that the server will respond with a 200 (OK) status code as default.
Using non-standard response codes
It really depends on what you are doing, but using response code values that are not part of the standard (ex. -999) may (or may not) error, but you should avoid that as it is not a supported standard.
Nullable Enum
For HttpStatusCodes in all cases (I have ever experienced) you cannot assign a null value to the HttpResponse as the property type is integer.
Note that what I am saying is specific to assigning a status code value to a HttpResponse object. You can read the other answers about the generic question of nullable enums.
Not unless you make your variable of a Nullable<MyEnum> (or MyEnum?) type.
Under the hood, enums are integers. When an enum is uninitialized, it has the default(int) value, which is 0.
Edit: other underlying types are possible, but the default is int. Whichever underlying type you use, an uninitialized enum will always be the default value of the underlying type.
When you don't assign integer values to your enum, the first option will be set to 0 and therefore be the default.
public enum MyEnum { Foo, Bar, Baz }
MyEnum myEnum;
if(myEnum == MyEnum.Foo) //true
if(myEnum == MyEnum.Bar) //false
if(myEnum == MyEnum.Baz) //false
When you do assign integer values to your enum, and there is no 0 (or unassigned) value, then your uninitialized enum will not match any of the options.
public enum MyEnum { Foo = 1, Bar = 2, Baz = 3 }
MyEnum myEnum;
if(myEnum == MyEnum.Foo) //false
if(myEnum == MyEnum.Bar) //false
if(myEnum == MyEnum.Baz) //false

Enum.Parse method returns a different enum member than the one passed into it as the parameter

I expect the following call to the Parse method to return the enum member EN_CA but it returns EN instead.
Enum.Parse(LanguageType, "EN_CA", true);
where:
enum LanguageType
{
EN = 0,
EN_CA = 0,
FR = 1
}
It seems like the Parse method just grabs the first member that maps to the value of the parameter that is passed into it.The Parse method seems to be loosing information during the conversion from string to enum member. Changing the order of EN_CA and EN would make the above call to return EN_CA but that is not going to solve the problem since it would cause a similar issue when calling the method for "EN".
Additional context related information: In my code, the LanguageType Enum is represent the index for a dictionary and these indices are used for localizing the language.
Does anyone have any idea of how to map two enum member to the same value while being able to get proper member from Enum.Parse? Do I just need to implement my own version of Enum.Parse which doesn't collapse the members with the same value into one?
An enum member is distinct from other enum members if and only if it has a different value. Effectively the members of the enumeration are named constants, with no real distinction between them other than the value they hold.
In your LanguageType enum you have two labels for the same value, and no way to distinguish them. Try this:
Console.WriteLine("{0} == {1} ? {2}",
LanguageType.EN.ToString(),
LanguageType.EN_CA.ToString(),
LanguageType.EN == LanguageType.EN_CA);
The output is:
EN == EN ? True
The same thing happens when you assign LanguageType.EN_CA to a variable, then examine the variable later to see what it contains. What you get is LanguageType.EN.
The key here is that the value of the member is all-important in most instances, with the position of the member being the tie-breaker during collisions. When two members have the same value the member that is declared first is the one that you will see whenever you do string conversions, including when you examine the value in the IDE.
So in effect you have a value LanguageType.EN_CA that is only an alias to the value LanguageType.EN.
While I can think of a couple of cute uses for this - like parsing incoming data that has multiple representations for the same value - it is really quite a terrible thing to do in most real-world environments, especially if you want to be able to do fully symmetric serialization/deserialization.
Now, as to your localization Dictionary...
It costs very little to store the same class object multiple times in a Dictionary, since class objects are stored by reference. Assuming you have a Localization class, the following code is not particularly inefficient in terms of storage:
enum LanguageType
{
EN, EN_CA, EN_US, EN_GB, EN_AU, FR
}
Dictionary<LanguageType, Localization> localizations = new Dictionary<LanguageType, Localization>();
localizations[LanguageType.EN] = new Localization("EN");
localizations[LanguageType.EN_CA] = localizations[LanguageType.EN];
localizations[LanguageType.EN_US] = localizations[LanguageType.EN];
localizations[LanguageType.EN_GB] = localizations[LanguageType.EN];
localizations[LanguageType.EN_AU] = localizations[LanguageType.EN];
Even if the Localization object contains a huge collection of resources, the above code only ever creates one instance of it. You get distinct values for the LanguageType members, and the Dictionary does the mappings for you.
You defined 0 twice in your enum - this will not work. Each value has to be unique or how else would an enum recognize its values - it is actually stored as integer.
Change it to:
enum LanguageType
{
EN = 0,
EN_CA = 1,
FR = 2
}
EDIT:
As pointed out by Greenish, you can define multiple names for the same value which acts as a sort of an alias. Using both or multiple names return the same value. If you try to get the string value from an integer value, you will get the first value defined for that integer.
In your case, you cannot achieve what you need using enums. You should probably build your own custom class to achieve that.
Enums basically are named integers. And it is possible to assign different names for a single number (as in your example for 0).
Enum.Parse searching for a first correct instance - and here you have a valid name as 0 == 0. So the solution is to change your numbers (or even just get rid of them as they are 0, 1, 2)
enum LanguageType
{
EN,
EN_CA,
FR
}
I thought of a way but it's messy fragile and naff. There again it illustrates the hole you have dug for yourself..
int index = Enum.GetNames(typeof(LanguageType)).indexof("EN_CA")
will give you 1
then something like
switch(index)
{
case 0 : return LanguageType.EN;
case 1 : return LangaugeType.EN_CA;
case 2 : return LanguageType.FR;
default : // throw some useful exception maybe
break
}
will return the member you want.
Horrible isn't it?
Enum.GetValues(typeof(LanguageType)) would return [0,0,1] and using indexof 0 on it is of course 0, which is why Parse is giving you the result it is.
The =0 specifies the representation of the enum's value in the underlying type (int). You've given both EN and EN_CA the same representation, namely 0, so now they've effectively become two labels for the same value.
Enum.Parse returns this value and it'll equal both labels.
The underlying problem is that you're trying to code a hierarchical concept, into a flat enum. For some purposes all english speaking cultures should be treated equal, for other purposes you'd like to distinguish between them.
The solution, I think, is to use the already present mechanisms for localizing your application, in particular CultureInfo should replace your enum and Resources your lookup dictionary.
I was a little surprised that this use of enum is allowed :)
But the MSDN documentation explicitly states it is valid and gives an example of how it can be useful:
enum Color
{
Red,
Green,
Blue,
Max = Blue
}
So here is how I fixed my problem:
I was not able to find a clean fix for the problem by getting Enum.Parse method return what I was expecting it to.(please see the note*)
My fix was to apply GroupBy(LanguageIndex) on the resulting dictionary which had its index duplicated and therefore throwing an exception. Since I wanted EN_CA and EN to have the same value in the enum that gave me what I was looking for without throwing an exception.
I can see that my fix is not an actual answer to the question that I initially asked, ignoring the context; though I though it might still be applicable to other contexts with a similar issue.
note* : I could have implemented my own version of Enum.Parse - Please see this answer for an alternative implementation - but that required me to put smelly hardcoded stuff into my code, so I just gave up on fixing the Parse method.

Are enum types stored as ints in C#?

Are enum types stored as ints in C#?
Will the enum below be represented as 0, 1, 2?
If not, what's the lightest way to define an enum?
public enum ColumnType
{
INT,STRING,OBJECT
}
From the MSDN
The default underlying type of enumeration elements is int.
By default, the first enumerator has the value 0, and the value of each successive enumerator is increased by 1.
So your assumptions are correct. Enums are stored as ints and your example will be represented as 0, 1, 2. However, you shouldn't rely on this and always refer to them by their assigned name just in case someone overrides the default.
Yes, an enum is stored as an int by default., as indicated here.
You can also specify the underlying type, e.g.:
enum Foo : short
{
Bar,
Baz
}
Although that usually isn't necessary.
By default yes:
http://msdn.microsoft.com/en-us/library/sbbt4032(v=vs.80).aspx
The enum keyword is used to declare an enumeration, a distinct type
consisting of a set of named constants called the enumerator list.
Every enumeration type has an underlying type, which can be any
integral type except char. The default underlying type of the
enumeration elements is int. By default, the first enumerator has the
value 0, and the value of each successive enumerator is increased by
1.
The default underlying type for an enum is an int, but different types can be used explicitly. For example, you can use byte:
enum Days : byte {Sat=1, Sun, Mon, Tue, Wed, Thu, Fri};
See http://msdn.microsoft.com/en-us/library/sbbt4032.aspx for details.
Every enumeration type has an underlying type, which can be any integral type except char.
Yes your enum be represented as 0,1,2 by default and it is the lightest way to define an enum
How ever you define enum by defining starting value as your requirement and assigning integral values explicitly to each of your enum member as well
The point about underlying types is already well-covered, so I'll add a different context:
At the IL / runtime level, instances of enums do not exist. They only exist:
a: to the compiler
b: to the runtime as a boxed value
c: in metadata (parameter/field/variable declarations)
At all other times, they are purely the integer-types values (most commonly int). The compiler uses enum variables (etc) for static analysis, overload resolution, etc but the opcodes it emits are identical to those it would have emitted for constant / literal integer values; i.e.
SomeEnum foo = SomeEnum.WithValueOne;
int bar = 1;
will have identical IL (except for the variable type, perhaps).
The only time it gets interesting is if emitting a box operation, or a call like .ToString() etc.
So: as long as you don't box them (store them in an object field/etc), then there is (at runtime) no significant difference between an enum or an integer when it comes to storage or performance (unless you use .ToString(), etc)

Should enums have uninitialized values .

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?
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.
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.
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.
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.
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.
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.

Categories

Resources