Why enums require an explicit cast to int type?
There are two primary and inconsistent uses of enums:
enum Medals
{ Gold, Silver, Bronze }
[Flags]
enum FilePermissionFlags
{
CanRead = 0x01,
CanWrite = 0x02,
CanDelete = 0x04
}
In the first case, it makes no sense to treat these things as numbers. The fact that they are stored as integers is an implementation detail. You can't logically add, subtract, multiply or divide Gold, Silver and Bronze.
In the second case, it also makes no sense to treat these things as numbers. You can't add, subtract, multiply or divide them. The only sensible operations are bitwise operations.
Enums are lousy numbers, so you should not be able to treat them as numbers accidentally.
Why must I use an explicit cast when using an enum in place of its underlying type?
Very simply because C# is strongly typed. An enum value is not of type byte even if you set it's translated values as byte, so you must cast it as byte before you can use it with a function that is expecting type byte. It's no different than casting another type.
Also, if your focus is on keeping things clean, you could consider rewriting (or overloading) your method slightly so that the cast is invisible to everything outside of it. It doesn't change the solution, but assuming you will be reusing the method in more than one place, it is less code:
public void AppendAsHex(StringBuilder sb, Foo b)
{
AppendAsHex(sb, (byte)b);
}
public void AppendAsHex(StringBuilder sb, byte b)
{
sb.AppendFormat("{0:X}", b);
}
At which point, this would work
Foo theDerp = Foo.DERP;
AppendAsHex(sb, theDerp);
Why do I have to explicitly cast an enum that I have specified the underlying type for?
This is a type safety feature. Implicit conversions have a long history of associated issues in C++, have a look at Stephen Dewhurst's book "C++ Gotchas" - the longest chapter is that on conversions.
Recall that an enumeration is nothing but a way to bind a constant value to a comprehensible name. This way, there is a finite, documented set of possible values, and by an implicit conversion, you massively extend the domain without giving any notice. Example:
void f(uint16_t arg); // arg can have 65536 different values
enum class Apples : uint16_t { GRANNY_SMITH = 1 }; // one possible value
If this compiles:
f(Apples::GRANNY_SMITH);
you have just given up the restrictiveness without giving notice. Instead,
f(static_cast<uint16_t>(Apples::GRANNY_SMITH));
is clearer and uglier. The clumsy nature of the cast tells you "why do you even do it?", and answering this question shouldn't be too easy. You created the enumeration to refer to possible values by typing out their associated names, right?
c# : Why is a cast needed from an Enum to an INT when used in a switch statement?, enums are ints
In C# enum
s aren't just numbers. Rather, they are numbers associated with the type or number with a name in a context.
To avoid casts in case
statements, you can do a cast in switch
:
switch((ViewBy)Convert.ToInt32(uxView.SelectedValue))
This, however, has its own problems. For example, this piece of code will write out 7
to the console.
enum ViewBy
{
ChuckNorris = 1,
JamesBond
}
Console.WriteLine((ViewBy)7);
Why do we need to type cast an enum in C#
With your updated example:
public class MyTest
{
public static int A =1;
}
And usage:
int a = MyTest.A;
That's not how enums look. Enums look more like (comments are places where we differ from a real enum):
public struct MyTest /* Of course, this isn't correct, because we'll inherit from System.ValueType. An enum should inherit from System.Enum */
{
private int _value; /* Should be marked to be treated specially */
private MyTest(int value) /* Doesn't need to exist, since there's some CLR fiddling */
{
_value = value;
}
public static explicit operator int(MyTest value) /* CLR provides conversions automatically */
{
return value._value;
}
public static explicit operator MyTest(int value) /* CLR provides conversions automatically */
{
return new MyTest(value);
}
public static readonly MyTest A = new MyTest(1); /* Should be const, not readonly, but we can't do a const of a custom type in C#. Also, is magically implicitly converted without calling a constructor */
public static readonly MyTest B = new MyTest(2); /* Ditto */
}
Yes, you can easily get to the "underlying" int value, but the values of A
and B
are still strongly typed as being of type MyTest
. This makes sure you don't accidentally use them in places where they're not appropriate.
Type-casting enum to integer and vice versa
enum
to int
is unambiguous cast (assuming C++ 03 where enum
is basically an int
), will be performed implicitly no problem. int
to enum
is potentially errorneous as it's a narrowing cast, not every int
value is a valid enum
value. That's why casting int
to enum
is only possible explicitly.
Same holds for C++ 11 and later standards, with the exception that C++ 11 introduced strongly typed enums and specific size enums.
Strongly typed enum is declared enum class
instead of just enum
, and it cannot be converted to an integer nor any other type, save for a user-defined conversion operator or function, or brute force (static_cast
). Sized enums are declared like this: enum Colors : char {...}
. This particular enum's values will have char
type instead of the default int
.
Related Topics
How to Check If Variable's Type Matches Type Stored in a Variable
How to Know User Has Clicked "X" or the "Close" Button
Cryptographicexception Was Unhandled: System Cannot Find the Specified File
How to Implement Recaptcha for ASP.NET MVC
C# Filestream:Optimal Buffer Size for Writing Large Files
How to Use ASP.NET Identity 2.0 to Allow a User to Impersonate Another User
Adding Headers When Using Httpclient.Getasync
How to Use Interface as a C# Generic Type Constraint
How to Specify a Generic Type in Xaml (Pre .Net 4 Framework)
.Net - Windowstyle = Hidden VS. Createnowindow = True
How to Do a Sha1 File Checksum in C#
How to Use C# to Sanitize Input on an HTML Page
Embed Unity3D App Inside Wpf Application
How to Check Whether an Object Has Certain Method/Property
How to Solve Operator '!=' Cannot Be Applied to Operands of Type 'T' and 'T'