How is it that an enum derives from System.Enum and is an integer at the same time?

admin

Administrator
Staff member
<strong>Edit</strong>: Comments at bottom. Also, <a href="http://philosopherdeveloper.wordpre...unbox-a-value-type-as-a-diff—wait-whats-this/" rel="nofollow noreferrer">this</a>.

<hr>

Here's what's kind of confusing me. My understanding is that if I have an enum like this...

Code:
enum Animal
{
    Dog,
    Cat
}

...what I've essentially done is defined a <em>value type</em> called
Code:
Animal
with two defined values,
Code:
Dog
and
Code:
Cat
. This type derives from the <em>reference type</em>
Code:
System.Enum
(something which value types can't normally do—at least not in C#—but which is permitted in this case), and has a facility for casting back and forth to/from
Code:
int
values.

If the way I just described the enum type above were true, then I would expect the following code to throw an
Code:
InvalidCastException
:

Code:
public class Program
{
    public static void Main(string[] args)
    {
        // Box it.
        object animal = Animal.Dog;

        // Unbox it. How are these both successful?
        int i = (int)animal;
        Enum e = (Enum)animal;

        // Prints "0".
        Console.WriteLine(i);

        // Prints "Dog".
        Console.WriteLine(e);
    }
}

<strong>Normally, <a href="http://philosopherdeveloper.wordpre...onverting-and-unboxing-read-my-mind-compiler/" rel="nofollow noreferrer">you cannot unbox a value type from
Code:
System.Object
as anything other than its exact type</a>.</strong> So how is the above possible? It is as if the
Code:
Animal
type <strong>is</strong> an
Code:
int
(not just <em>convertible</em> to
Code:
int
) and <strong>is</strong> an
Code:
Enum
(not just <em>convertible</em> to
Code:
Enum
) at the same time. <strike>Is it multiple inheritance? Does
Code:
System.Enum
somehow inherit from
Code:
System.Int32
(something I would not have expected to be possible)?</strike>

<strong>Edit</strong>: It can't be either of the above. The following code demonstrates this (I think) conclusively:

Code:
object animal = Animal.Dog;

Console.WriteLine(animal is Enum);
Console.WriteLine(animal is int);

The above outputs:

True
False

Both <a href="http://msdn.microsoft.com/en-us/library/sbbt4032(v=vs.71).aspx" rel="nofollow noreferrer">the MSDN documentation on enumerations</a> and the C# specification make use of the term "underlying type"; but I don't know what this means, nor have I ever heard it used in reference to anything other than enums. What does "underlying type" actually <em>mean</em>?

<hr>

So, is this yet another <a href="https://stackoverflow.com/questions...oxing-unboxing-behavior-of-nullablet-possible">case that gets special treatment from the CLR</a>?

My money's on that being the case... but an answer/explanation would be nice.

<hr>

<strong>Update</strong>: <a href="https://stackoverflow.com/questions...is-an-integer-at-the-same-tim/4627345#4627345">Damien_The_Unbeliever</a> provided the reference to truly answer this question. The explanation can be found in Partition II of the CLI specification, in the section on enums:

<blockquote>
For binding purposes (e.g., for
locating a method definition from the
method reference used to call it)
enums shall be distinct from their
underlying type. For all other
purposes, including verification and
execution of code, <strong>an unboxed enum
freely interconverts with its
underlying type</strong>. Enums can be boxed
to a corresponding boxed instance
type, but this type is <em>not</em> the same
as the boxed type of the underlying
type, so boxing does not lose the
original type of the enum.
</blockquote>

<strong>Edit (again?!)</strong>: Wait, actually, I don't know that I read that right the first time. Maybe it doesn't 100% explain the specialized unboxing behavior itself (though I'm leaving Damien's answer as accepted, as it shed a great deal of light on this issue). I will continue looking into this...

<hr>

<strong>Another Edit</strong>: Man, then <a href="https://stackoverflow.com/questions...is-an-integer-at-the-same-tim/4627416#4627416">yodaj007's answer</a> threw me for another loop. Somehow an enum is not exactly the same as an
Code:
int
; yet an
Code:
int
can be assigned to an enum variable <em>with no cast</em>? Buh?

I think this is all ultimately illuminated by <a href="https://stackoverflow.com/questions...is-an-integer-at-the-same-tim/4627431#4627431">Hans's answer</a>, which is why I've accepted it. (Sorry, Damien!)