为什么这个枚举声明现在起作用了?
Why is this enum declaration working now?
在回答另一个问题时,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 中的一个更改,尚未记录在案,很快就会记录下来,您可以从 git 问题中阅读 Roslyn Github
要么是新编译器的疏忽,要么他们决定不再在语言中出现这种不一致(?)。
目前似乎没有官方规范,只有一个看起来不太官方的 git 存储库,其中正在做工作:
https://github.com/ljw1004/csharpspec/blob/gh-pages/enums.md
目前看来,不使用底层枚举类型的别名应该是个错误。该语言看起来与以前的官方规范相同。但是由于编译器和规范似乎仍在进行中,所以很难说哪个是正确的。
这在 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 根本不检查它,而是解析 any 类型:
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并没有太大区别。因此,任何类型限制都不适用于语法级别,而是适用于语义级别——此时类型别名可能已经被评估。
所以这似乎是一个错误:要么在规范中,要么在解析器中。鉴于该规范仍在进行中,这可能会在以后修复。
这是 C# 6 中有意的语言更改,其规范仅以草案形式发布。这是一个很小的变化,以至于我们一直忘记将其放入规格中。
在回答另一个问题时,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 中的一个更改,尚未记录在案,很快就会记录下来,您可以从 git 问题中阅读 Roslyn Github
要么是新编译器的疏忽,要么他们决定不再在语言中出现这种不一致(?)。
目前似乎没有官方规范,只有一个看起来不太官方的 git 存储库,其中正在做工作:
https://github.com/ljw1004/csharpspec/blob/gh-pages/enums.md
目前看来,不使用底层枚举类型的别名应该是个错误。该语言看起来与以前的官方规范相同。但是由于编译器和规范似乎仍在进行中,所以很难说哪个是正确的。
这在 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 根本不检查它,而是解析 any 类型:
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并没有太大区别。因此,任何类型限制都不适用于语法级别,而是适用于语义级别——此时类型别名可能已经被评估。
所以这似乎是一个错误:要么在规范中,要么在解析器中。鉴于该规范仍在进行中,这可能会在以后修复。
这是 C# 6 中有意的语言更改,其规范仅以草案形式发布。这是一个很小的变化,以至于我们一直忘记将其放入规格中。