为什么这个枚举声明现在有效?

时间:2016-06-02 10:18:47

标签: c# .net enums c#-6.0

在回答另一个问题时,Jon Skeet提到enums的定义有一个奇怪的事情。 His answer.

他声明只能使用类型别名来重新定义enum的基础类型,而不能使用框架类型(int是有效的,Int32不是,等等)。

public enum Foo : UInt32 {} // Invalid
public enum Bar : uint   {} // Valid

现在我试图重现(在VS2015中使用C#6 / Roslyn),我没有得出相同的结论:

public enum TestEnum : UInt32
{

}

public enum MyEnum : uint
{

}

都是完全有效的。为什么会这样?或者有什么变化?

修改

所以为了澄清事情,这是C#6中的一个变化,尚未被记录,并且很快就会记录下来,因为你可以在Roslyn Github

3 个答案:

答案 0 :(得分:6)

现在使用C#6,这当然很奇怪。当前正在进行的规范仍然列出了以下用于在enum declarations中指定基数的语法:

enum_base
    : ':' integral_type
    ;

整数类型定义为actual fixed tokens

integral_type
    : 'sbyte'
    | 'byte'
    | 'short'
    | 'ushort'
    | 'int'
    | 'uint'
    | 'long'
    | 'ulong'
    | 'char'
    ;

根据此语言规范判断,解析器应拒绝使用未出现在该静态类型标识符列表中的其他基本类型,并导致语法错误。

鉴于这不是发生的事情,有两种可能性:要么故意更改解析器以接受那里的非别名类型,要么解析器错误地接受它们。

如果我们看看Roslyn的实现,那么我们就可以看到为什么规范中的这个要求没有得到强制执行。 enum declaration parser根本不检查它,但解析任何类型:

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);
}

此时,它与code for “normal” inheritance并没有多大差别。因此,任何类型限制都不适用于语法级别,而是适用于语义级别 - 此时可能已经评估了类型别名。

所以这似乎是一个错误:无论是在规范中,还是在解析器中。鉴于规范仍在进行中,这可能会在以后修复。

答案 1 :(得分:2)

要么是新编译器的疏忽,要么他们决定不再在语言中出现这种不一致(?)。

目前似乎没有官方规范,只有一个看起来不那么官方的git存储库正在进行工作:

https://github.com/ljw1004/csharpspec/blob/gh-pages/enums.md

目前看起来没有使用底层枚举类型的别名应该是一个错误。该语言看起来与之前的官方规范相同。但由于编译器和规范似乎仍在进行中,因此很难说哪一个是正确的。

答案 2 :(得分:1)

这是C#6中的故意语言更改,其规格仅以草稿形式发布。这是一个很小的变化,我们一直忘记把它放到规格中。

另见https://github.com/dotnet/roslyn/issues/623