While answering another question, Jon Skeet mentioned that there is a weird thing going on with the definition of enums
. His answer.
He states that redifining the underlying type of an enum
is only possible with the type-aliases and not with the framework types (int
is valid, Int32
not, etc.)
public enum Foo : UInt32 {} // Invalid
public enum Bar : uint {} // Valid
Now I tried to reproduce that (with C#6/Roslyn in VS2015), and I didn't come to the same conclusion:
public enum TestEnum : UInt32
{
}
and
public enum MyEnum : uint
{
}
are both totally valid. Why is that so? Or has what changed?
EDIT:
So to clear up things, it was a change in C#6, that has not been documented yet, and it will be documented soon, as you can read from this git issue on the Roslyn Github
It’s certainly odd that this is working now with C# 6. The current in-progress specification still lists the following grammar for specifying a base in enum declarations:
enum_base
: ':' integral_type
;
And the integral types are defined as actual fixed tokens:
integral_type
: 'sbyte'
| 'byte'
| 'short'
| 'ushort'
| 'int'
| 'uint'
| 'long'
| 'ulong'
| 'char'
;
Judging by this language specification, using some other base type that does not appear in that list of static type identifiers should be rejected by the parser and cause a syntax error.
Given that that’s not what happens, there are two possibilities: Either the parser was changed deliberately to accept the non-aliased types there, or the parser incorrectly accepts those.
If we look at the implementation of Roslyn, then we can see why this requirement in the specification is not enforced. The enum declaration parser simply does not check for it but parses any type:
BaseListSyntax baseList = null;
if (this.CurrentToken.Kind == SyntaxKind.ColonToken)
{
var colon = this.EatToken(SyntaxKind.ColonToken);
var type = this.ParseType(false);
var tmpList = _pool.AllocateSeparated<BaseTypeSyntax>();
tmpList.Add(_syntaxFactory.SimpleBaseType(type));
baseList = _syntaxFactory.BaseList(colon, tmpList);
_pool.Free(tmpList);
}
At this point, it does not really differ much from the code for “normal” inheritance. So any type restriction does not apply on the syntax level, but on the semantic level—at which point type alias are probably already evaluated.
So this seems to be a bug: Either in the specification, or in the parser. Given that the specification is still a work in progress, this might be fixed later.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With