1) I’m aware of the following benefits:
they increase the level of abstraction since you immediately see what underlying开发者_运维知识库 integral values represent.
You can use them instead of magic numbers and by doing that making the code more understandable
They also restrict the values an
enum
variable can have and in doing so make the application safer, since programmers know which values are valid for variable, so I guess they sort of provide a type safety
Are there any other benefits they provide over directly using integral values?
2) Why do they use integrals as an underlying type and not string?
thank you
You've listed a lot of the core reasons where enums are preferable to integral types.
Named constants are safer and more readable than magic numbers
Enums describe to programmers what they are for. Integral values don't.
Naturally limiting the set of values that can be passed in. (You've got the tip of the type-safety iceberg... but look deeper...)
You can also add:
Vastly increased Type Safety. If you accept an 'int', then any int can be passed in. If you accept a VehicleType, then only a VehicleType can be passed in. I'm not just talking about someone passing in 6 when the largest allowed number is 5. I mean what if you pass in FuelType.Unleaded to a function that thinks it means VehicleType.Aeroplane? With enums the compiler will tell you you're an idiot. An integral type says "yeah, 5 is fine with me" and your program exhibits really odd behaviour that may be extremely difficult to trace.
Easier refactoring. Just as with any magic constants, If you pass in the value 5 in a hundred places in your program, you're in trouble if you decide to change 5 to have a different meaning. With an enum (as long as you don't have binary backwards compatibility concerns) you can change the underlying values. You can also change the underlying type of an enum if you wish (byte -> int -> long) without having to do anything more than recompile the client code.
Bitfields are so much easier to work with when the bits and masks can be named. And if you add new bits, you can often arrange things so that merely updating the related masks will allow most of your existing code to handle the new bitfields perfectly without having to rewrite them from scratch.
Consistency throughout the program. If you are careful with obfuscation and type safety, enums allow you to represent a list of named values that a user chooses from with the same names in the code, but without the efficiency cost of using strings.
Everybody understands why constants are great in code. Enums simply give you a way of holding together a related group of constants. You could achieve the same thing in a messier manner using a namespace of consts.
Using an enum for a parameter rather than a bool not only makes the code self-documenting, readable, and less prone to mistakes. It also makes it much easier to add a third option when you realize that two options isn't enough.
As with all tools, enums can be misused. Just use them where they make sense.
2) Why use bytes or ints instead of strings? Simply they're small and efficient.
I would conjecture that they require underlying integral types to ensure simplicity of comparison and more easily support bit flags. Without that limitation, we, or the compiler, or the runtime, would likely have to resort to some fuzziness to do things like combinations - or we would get into a situation where - as you say - we shouldn't care about the underlying type (the point of the abstraction) and yet when we try to say A | B
we get a runtime error because we used an underlying type that isn't capable of that type of operation.
One benefit is when you want to use enum as a flag.
So if you define an enum like this:
[Flags]
public enum TestEnum{ A, B, C, D };
Then if you have a method that accept an instance of TestEnum as a variable, you can combine the values from the enum, so you can send for example A | B | C
as the parameter for the method. Then, inside the method, you can check the parameter like this:
if ((paramname & TestEnum.A) > 0)
{
//do things related to A
}
if ((paramname & TestEnum.B) > 0)
{
//do things related to B
}
//same for C and D
Also, I think the reasons you mention are good enough by themselves to use enums.
Also regarding the comment that you can force an wrong value into an enum with code like this (TestEnum)500;
it's hard to do if you do not want to break your code.
The point that the value 0 for an enum should be the default value, or in the case of flags "the absence of all other flags" is very important, since the line TestEnum myenum
will instanciate myenum as 0 regardless if you have defined any enum value for 0 or not.
You can also parse an Enum from the string representation. You may get that string from a data source or user-entry.
I think you sold me on Enums at "magic numbers".
The main benefit of enum is that constants can be referred to in a consistent, expressive and type safe way. Readability is of-course the topmost advantage of using the enumeration.
Another advantage is that enumerated constants are generated automatically by the compiler.
For instance, if you had an enumerated constant type for error codes that could occur in your program, your enum definition could look something like this:
enum Error_Code
{
OUT_OF_MEMORY,
FILE_NOT_FOUND
};
OUT_OF_MEMORY is automatically assigned the value of 0 (zero) by the compiler
because it appears first in the definition.FILE_NOT_FOUND equal to 1, so on.
If you were to approach the same example by using symbolic constants or Magic numbers, you write much more code to do the same.
精彩评论