Reputation:
I am wondering why it is that a single implicit conversion to an enum value doesn't work the same way it would if the conversion were to a system type. I can't see any technical reason however maybe someone smarter than I can shed some light for me.
The followoing fails to compile with, "A value of an integral type expected"
and "Cannot implicitly convert type 'Test.En' to 'Test.Foo"
.
void test1 (){
Foo f = new Foo();
switch (f) // Comment this line to compile
//switch ((En)f) // Uncomment this line to compile
{
case En.One:
break;
}
}
//////////////////////////////////////////////////////////////////
public enum En
{
One,
Two,
Three,
}
public class Foo
{
En _myEn;
public static implicit operator En(Foo f)
{
return f._myEn;
}
}
edit from the spec:
The governing type of a switch statement is established by the switch expression. If the type of the switch expression is sbyte, byte, short, ushort, int, uint, long, ulong, char, string, or an enum-type, then that is the governing type of the switch statement. Otherwise, exactly one user-defined implicit conversion (§6.4) must exist from the type of the switch expression to one of the following possible governing types: sbyte, byte, short, ushort, int, uint, long, ulong, char, string. If no such implicit conversion exists, or if more than one such implicit conversion exists, a compile-time error occurs.
To Clarify the question, why is an enum-type not included with the list of allowed user-defined implicit conversions?
Upvotes: 4
Views: 1159
Reputation: 660148
The language design notes archive does not provide a justification for this decision. This is unfortunate, since the decision was changed. As you can see, the design evolved over time:
Notes from May 26th, 1999:
What types are allowed in as the argument to a switch statement? integral types including char, enum types, bool. C# also permits types that can be implicitly and unambiguously converted to one of the aforementioned types. (If there are multiple implicit conversion, then its ambiguous and a compile-time error occurs.) We're not sure whether we want to support string or not.
June 7th, 1999:
We discussed enabling switch on string arguments. We think this is a good feature – the language can add value by making this common case easier to write, and the additional complexity for the user is very low.
December 20th, 1999:
It is illegal to switch on an expression of type bool. It is legal to switch on an expression of an integral type or string type. It is legal to switch on an expression of a type that has exactly one implicit conversion to an integral type or string type.
Here we have the first occurence of the rule in question. Enums seem to have disappeared. And why not use user-defined implicit conversions to enum? Was this simply an oversight? The designers did not record their thoughts.
Note that the first sentence is NOT what we implemented. It is unclear to me why the implementors did the opposite of what the design committee recommended. This comes up again in the notes several years later:
August 13, 2003:
The compiler allows switch on bool. Don’t want to document this and add it to the language. Don’t want to remove it for compatibility reasons. Decided to silently continue to support switch on bool.
I decided that this was silly; when we produced the annotated print edition of the C# 3.0 specification, I added bool (and bool?) to the list of legal governing types.
In short: the whole thing is a bit of a mess. I have no idea why enums were in, then out, then half-in-half-out. This might have to remain one of the Mysteries of the Unknown.
Upvotes: 5
Reputation: 39437
Because enums are treated as integers for the purpose of switching, and as i've asked before, the compiler doesn't do multiple implicit conversions to get to a usable type, it can't figure out how to switch on foo.
My only theory as to why enums can't be used like that is that enums are not an integer type in and of themselves, and thus the compiler would have to do multiple implicit conversions to get to an integer primitive from foo.
I compiled then reflected your code and here's the results:
public static void Main()
{
Foo f = new Foo();
f._myEn = En.Three;
switch (f)
{
case En.One:
{
}
}
}
So apparently under the covers it does do an implicit conversion. :S
Upvotes: 1
Reputation: 33474
void test1 (){
Foo f = new Foo();
En n = f;
switch (n)
{
case En.One:
break;
}
}
EDIT: Since switch
expects an integral value, writing switch(f)
makes the compiler look for conversion from an instance of Foo
to an integral type, which doesn't exist.
Upvotes: 0
Reputation: 4005
What if your class contained two enums and had implicit conversion operators for both? Or better yet, what if you had implicit conversion operators for an enum and int? Which conversion would the compiler "automatically" pick for you when you write a switch statement?
You have to explicitly specify what type of object is being used inside the switch statement. Implicit operators just tell the compiler/runtime "if you have a Foo and need an En, this code does that". It does not change the actual underlying type of the object.
Upvotes: -1
Reputation: 59993
Take a look at that second error message. The compiler is trying to type-coerce the enum to match the type of what is in the switch statement.
As a point of interest, how does this fare?
void test2 (){
Foo f = new Foo();
switch (En.One)
{
case f:
break;
}
}
Upvotes: -2