9

C#3 (Visual Studio 2008) introduced a breaking change to the language (http://msdn.microsoft.com/en-us/library/cc713578.aspx, see change 12) that allows any literal zero to be implicitly converted to an Enum. This seems odd in many ways. Does anyone know why this is part of the spec? Why not a literal one? Or seven? Why is zero special? And it makes some very counterintuitive overload resolution choices. For instance.

function string F(object o) { return o.ToString(); }
function string F(DbType t) { return t.ToString(); }
int i = 0;
F((long)0) == "String" // would have been "0" in VS 2005
F(0) == "String"
F(i) == "0"

Very confusing, and an intentionally introduced breaking change to the language. Any ideas?

Sebastian Good
  • 6,310
  • 2
  • 33
  • 57
  • If you are going to make such a drastic change to a question (especially one that already with up voted to answers), it would be best -- for the answerers, browsers, and you -- to create a new question. You will now have answers to two different questions, the first of which casual browsers will probably never see in the edit history. – joshperry Oct 27 '09 at 20:01
  • and like magic, the question has been edited back to its original misleading form! it needs to be noted that the sample given is not broken in VS 2008. i will make that change and see if it sticks... – Sebastian Good Oct 27 '09 at 20:37

5 Answers5

10

C# has always allowed the implicit conversion of the literal 0 to any Enum value. What has changed is how the rule is applied to other constant expressions. It was made to be more consistent and allow any constant expressions which evaluates to 0 to be implicitly convertible to an enum.

The example you gave produces the same behavior in all versions of C#.

Here is an example of changed behavior (directly from the linked documentation)

public enum E
{
    Zero = 0,
    One = 1,
} 

class A
{
    public static A(string s, object o)
    { System.Console.WriteLine("{0} => A(object)", s); } 

    public static A(string s, E e)
    { System.Console.WriteLine("{0} => A(Enum E)", s); }

    static void Main()
    {
        A a1 = new A("0", 0);
        A a3 = new A("(int) E.Zero", (int) E.Zero);
    }
}

Visual C# 2005 output:

0 => A(Enum E)
(int) E.Zero => A(object)

Visual C# 2008 output:

0 => A(Enum E)
(int) E.Zero => A(Enum E)
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • Ah, a good point. The example from our application was actually where the programmer used (long) 0. Perhaps in an earlier version that did not trigger the 'constant expression' rule. The question still stands: why if no other integer is implicitly convertible to an Enum is zero? – Sebastian Good Oct 27 '09 at 19:48
  • @Sebastian, I'm not certain on this point. There is probably a very interesting language reason why and hopefully Eric will be around later to comment on this . – JaredPar Oct 27 '09 at 19:52
  • A constant expression is any expression that can be determined at compile-time to result in a constant value (the value of the result of the expression could be replaced in the source code with no side-effects). In VS 2005 only "literal" zeros were implicitly converted to enums, in >=VS 2008 any "constant expression" that evaluates to zero will be implicitly converted. – joshperry Oct 27 '09 at 19:55
4

I would guess that it is because 0 is considered the "Default Value" of enums.

C# (default keyword was introduced in C# 2.0)

enum DbType {
    Unspecified,
    SqlServer
}

DbType t;
int i = 0;

Console.WriteLine(t == i);
Console.WriteLine(i == default(DbType));

Outputs:

True
True
joshperry
  • 41,167
  • 16
  • 88
  • 103
  • I imagine it's pretty much precisely because `default(T)` didn't exist in 1.0, and they didn't want to have an inconsistency in the language where you could get enum variable default-initialized to `0` implicitly, but not explicitly (without a cast). – Pavel Minaev Oct 27 '09 at 19:52
  • @Pavel Minaev -- I like this theory. – Sebastian Good Oct 27 '09 at 20:09
2

It has been allowed since version 1.0. It is the default value of an enum.

"A literal 0 is implicitly convertible to any enum type. In Visual C# 2005 and earlier versions of the compiler, there are also some constant expressions that evaluate to 0 that can implicitly convert to any enum type, but the rule that determines which of these expressions are convertible is unclear. In Visual C# 2008, all constant expressions that are equal to 0 can be implicitly converted to any enum type."

leppie
  • 115,091
  • 17
  • 196
  • 297
0

"The default underlying type of the enumeration elements is int. By default, the first enumerator has the value 0, and the value of each successive enumerator is increased by 1." - This is from MSDN notes for 1.1 framework, so it's always been the case.

Dan Diplo
  • 25,076
  • 4
  • 67
  • 89
0

As others have mentioned, 0 is the default enum. Try to think of enumerations as follows (in a more explicit fashion):

public enum HairColor
{
    Blonde           = 0x0000;
    Brunett          = 0x0001;
    Red              = 0x0002;
    StrawberryBlonde = 0x0004;
}

Because you are not being explicit in your values of a given enumeration, C# will automagically assign it a default value. If you don't want that, then you will have to explicitely define the values for a given enumeration.

Wayne Hartman
  • 18,369
  • 7
  • 84
  • 116