<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...
...what I've essentially done is defined a <em>value type</em> called
with two defined values,
and
. This type derives from the <em>reference type</em>
(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
values.
If the way I just described the enum type above were true, then I would expect the following code to throw an
:
<strong>Normally, <a href="http://philosopherdeveloper.wordpre...onverting-and-unboxing-read-my-mind-compiler/" rel="nofollow noreferrer">you cannot unbox a value type from
as anything other than its exact type</a>.</strong> So how is the above possible? It is as if the
type <strong>is</strong> an
(not just <em>convertible</em> to
) and <strong>is</strong> an
(not just <em>convertible</em> to
) at the same time. <strike>Is it multiple inheritance? Does
somehow inherit from
(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:
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
; yet an
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!)
<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
Code:
Dog
Code:
Cat
Code:
System.Enum
Code:
int
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
Code:
Animal
Code:
int
Code:
int
Code:
Enum
Code:
Enum
Code:
System.Enum
Code:
System.Int32
<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
Code:
int
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!)