C#编译器的颜色颜色规则是否与consttypes成员错误?

好的,所以C#语言规范在Color Color规则中有一个特殊的部分(旧版本链接) ,其成员和types具有相同的名称。 着名的上师埃里克·利波特(Eric Lippert) 曾经对此进行了博客 。

我在这里要问的问题在某种意义上(而不是)与在线程循环定义中提到的常量枚举中的问题完全相同。 如果你喜欢,你可以去争取另一个问题。

现在我的问题。 考虑这个代码:

 namespace N { public enum Color { Green, Brown, Purple, } public class C1 { public const Color Color = Color.Brown; // error CS0110 - WHY? Compiler confused by Color Color? } public class C2 { public static readonly Color Color = Color.Brown; // fine } public class C3 { public static Color Color = Color.Brown; // fine } public class C4 { public Color Color = Color.Brown; // fine } } 

这里的要点是,在上面的每种情况下,最右边的标识符Color可以引用enumtypes,也可以引用具有相同名称的类成员。 但是上面提到的Color Color规则意味着我们应该看看成员( Brown )是静态的还是非静态的。 由于在这种情况下是静态的,我们应该相应地解释Color

我明显的主要问题: 为什么这不适用于一个consttypes的成员? 这是无意的吗?

(显然,说N.Color.BrownN是命名空间)“修复”它,我不是在问这个!)


注意:使用局部variablesconst ,上面的exception不存在:

  public class C5 { public Color Color; void M() { const Color Color = Color.Brown; // works (no warning for not using local variable?) } } public class C6 { public Color Color; void M() { const Color other = Color.Brown; // works (warning CS0219, 'other' not used) } } 

这是一个错误。 我无法在VS 2015的CTP 5中重现这个问题,我认为这个问题应该作为Roslyn重写的一部分被修复。 但是,下面的一位评论者指出,他们可以在CTP 6中复制它。所以我不确定这个bug是否已经被修复。

个人logging:我没有具体回顾,如果我在2010年首次报告这个问题时负责研究这个问题,但由于我在那时做了很多圆形探测器的工作,所以几率相当不错。

这远不是圆形探测器中唯一的缺陷。 如果嵌套genericstypes又有generics基types,其types参数涉及嵌套types,那么它会变得相当困惑。

亚历克斯“不会修复”这个,我一点也不觉得奇怪, 我花了相当长的时间重写了循环检测的代码,这个变化被认为太冒险了。 所有的工作都被踢到了罗斯林。

如果您有兴趣了解Color颜色绑定代码在Roslyn中的工作原理,请参阅BindLeftOfPotentialColorColorMemberAccess名为BindLeftOfPotentialColorColorMemberAccess的适当命名方法 – 我喜欢使用一些描述性方法名称。

1)它不能用于const因为它试图同时允许两个定义(枚举types和类成员),所以它试图将自己定义为一个函数本身。

2)是不是意想不到的? 有点。 这是一个意想不到的行为的意外结果。

基本上,这是微软承认的一个错误,但是已经提交为“无法修复”, 这里logging了连接。

我无法在任何地方在线find5.0语言规范(文章或博客forms),但如果您有兴趣,可以在这里下载。 我们对第161页第7.6.4节“成员访问”感兴趣,它是第一个7.6.4.1节,它是OP链接到的那一节(当时是7.5.4.1)。

即使你的标识符现在有两个单独的含义,你可以命名一个成员和一个types完全相同的名称(例如,颜色)的事实是明确允许的。 这里是规范的语言:

7.6.4.1相同的简单名称和types名称在表单EI的成员访问中,如果E是单个标识符,并且E作为简单名称(第7.6.2节)的含义是常量,字段,属性,局部variables或与E的含义types相同的参数作为types名称(§3.8),那么E的可能含义都是允许的。 EI的两个可能的含义从来都不含糊,因为在这两种情况下,我必须是E类的成员。 换句话说,规则只是允许访问E的静态成员和嵌套types,否则会发生编译时错误。 例如:

 struct Color { public static readonly Color White = new Color(...); public static readonly Color Black = new Color(...); public Color Complement() {...} } class A { public Color Color; // Field Color of type Color void F() { Color = Color.Black; // References Color.Black static member Color = Color.Complement(); // Invokes Complement() on Color field } static void G() { Color c = Color.White; // References Color.White static member } } 

这是关键部分:

E的可能含义是允许的。 EI的两个可能的含义从来都不含糊,因为在这两种情况下,我必须是E类的成员。 换句话说,规则只是允许访问E的静态成员和嵌套types,否则会发生编译时错误。

当你定义Color Color = Color.Brown ,东西会改变。 由于我(布朗)在这两种情况下(静态和非静态) 必须是E(颜色)的成员,因此此规则允许您访问两者,而不是由于当前(非静态)上下文而限制一个。 然而,现在你已经把上下文(你的非静态的)作为一个常量。 既然它允许这两个,它试图将Color.Brown定义为枚举和类成员,但是根据它自己的值(例如,不能有const I = I + 1 ),它有一个问题。

我确定这与常量的值在编译时必须是确定性有关,但(静态)属性的值将在运行时确定。

Interesting Posts