C#编译器是否使用const类型成员获取Color Color规则?

Jep*_*sen 37 c# language-lawyer member-access

好的,所以C#语言规范在规则上有一个特殊的部分(旧版链接),Color Color其中一个成员及其类型具有相同的名称.着名的大师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
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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


附注:使用局部变量const,上述异常不存在:

    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)
        }
    }
Run Code Online (Sandbox Code Playgroud)

Eri*_*ert 27

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

在个人方面:我没有特别回想一下,当我在2010年首次报道时,我是否负责调查这个,但由于我在那时对圆度探测器做了大量工作,可能性非常好.

这远不是圆形探测器中唯一的错误; 如果存在嵌套泛型类型,那么它会变得相当混乱,而这些泛型类型又具有通用基类型,其类型参数涉及嵌套类型.

亚历克斯"不会修复"这个,我并不感到惊讶; 我花了很长时间重写了进行类循环检测的代码,这种变化被认为风险太大.所有这些工作都被罗斯林抨击了.

如果您有兴趣了解Color Color绑定代码如何在Roslyn中运行,请查看恰当命名的方法BindLeftOfPotentialColorColorMemberAccess- 我爱我一些描述性的方法名称 - 在Binder_Expressions.cs.


Dre*_*dan 13

1)它不适用于a,const因为它试图同时允许两个定义(枚举类型和类成员),因此它尝试将自身定义为自身的函数.

2)是无意的吗?有点.这是预期行为的意外后果.

基本上,这是微软承认的一个错误,但已经提交为"Will Not Fix",在此处记录了Connect .

我无法在任何地方找到5.0语言规范(文章或博客形式),但如果您有兴趣,可以在这里下载.我们感兴趣的是第161页第7.6.4节,成员访问,它是第一部分7.6.4.1,它与OP链接的部分相同(当时为7.5.4.1).

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

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

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 
    } 
}
Run Code Online (Sandbox Code Playgroud)

这是关键部分:

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

当你定义时Color Color = Color.Brown,会发生一些变化.由于I(Brown)在两种情况下都必须是E(Color)的成员(静态和非静态),因此该规则允许您访问两者,而不是由于当前(非静态)上下文而限制一个.但是,现在您已将其中一个上下文(您的非静态上下文)设为常量.因为它同时允许,它试图定义Color.Brown两个枚举和类的成员,但有它取决于它自身的价值(你不能有一个问题const I = I + 1为例).