C# 编译器是否将 Color Color 规则错误地用于 const 类型成员?
Does the C# compiler get the Color Color rule wrong with const type members?
好的,所以 C# 语言规范有 a special section (old version linked) on the Color Color
rule where a member and its type has the same name. Well-known guru Eric Lippert once blogged 关于它。
我在这里要问的问题在某种意义上(不)与线程 Circular definition in a constant enum 中提出的问题完全相同。如果你愿意,你可以去给另一个问题投票。
现在是我的问题。考虑这段代码:
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
可以指代 enum
类型,也可以指代具有相同名称的 class 成员.但是上面说的Color Color
规则就是说我们要看成员(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)
}
}
我确信这与常量的值在编译时必须是确定的这一事实有关,但(静态)属性 的值将在 运行-时间。
1) 它不适用于 const
因为它试图同时允许两种定义(枚举类型和 class 成员),所以它试图将自己定义为自身的一个功能。
2) 是无意的吗?有点。这是预期行为的意外后果。
基本上,这是 Microsoft 承认但已归档为“不会修复”的错误,记录在 Connect here。
我在任何地方都找不到 5.0 语言规范(以文章或博客的形式),但如果您有兴趣,可以下载它 here。我们对第 161 页的第 7.6.4 节“成员访问”感兴趣,它是第 7.6.4.1 节,与 OP 链接到的同一节(当时是 7.5.4.1)。
您可以为成员和类型命名完全相同的名称(例如,Color)这一事实是明确允许的,即使您的标识符现在具有两个不同的含义。这是规范的语言:
7.6.4.1 Identical simple names and type names In a member access of the form E.I, if E is a single identifier, and if the meaning of E as
a simple-name (§7.6.2) is a constant, field, property, local variable,
or parameter with the same type as the meaning of E as a type-name
(§3.8), then both possible meanings of E are permitted. The two
possible meanings of E.I are never ambiguous, since I must necessarily
be a member of the type E in both cases. In other words, the rule
simply permits access to the static members and nested types of E
where a compile-time error would otherwise have occurred. For example:
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 的两种可能含义。 E.I 的两种可能含义绝不会含糊不清,因为在这两种情况下 I 都必须是类型 E 的成员。换句话说,该规则只允许访问 E 的静态成员和嵌套类型,否则会发生编译时错误。
当您定义 Color Color = Color.Brown
时,有些事情会发生变化。由于 I (Brown) must 在两种情况下(静态和非静态)都是 E(Color)的成员,因此此规则允许您访问两者,而不是由于当前(非静态)上下文。但是,现在您已经将其中一个上下文(您的非静态上下文)设为常量。因为它允许两者,所以它试图将 Color.Brown
定义为 both 枚举和 class 成员,但是它有一个问题取决于它自己的价值(你例如不能有 const I = I + 1
)。
这是一个错误。我无法在 VS 2015 的 CTP 5 中重现这个问题,我认为这个应该作为 Roslyn 重写的一部分得到修复。然而,下面的评论者指出他们可以在 CTP 6 中重现它。所以我不确定这里发生了什么,至于这个错误是否已被修复。
就个人而言:我不记得在 2010 年首次报道时我是否负责调查这个问题,但由于当时我在圆度检测器上做了很多工作,所以可能性是非常好。
这远不是圆度检测器中存在的唯一错误;如果存在嵌套的泛型类型,而嵌套的泛型类型又具有其类型参数涉及嵌套类型的泛型基类型,它会变得非常混乱。
亚历克斯"won't fix"编了这个我一点也不惊讶;我花了很长时间重写执行 class 循环检测的代码,并且更改被认为风险太大。所有这些工作都交给了 Roslyn。
如果您有兴趣了解 Color Color 绑定代码在 Roslyn 中的工作原理,请查看恰当命名的方法 BindLeftOfPotentialColorColorMemberAccess
-- 我喜欢一些描述性的方法名称 -- 在 Binder_Expressions.cs
.
好的,所以 C# 语言规范有 a special section (old version linked) on the Color Color
rule where a member and its type has the same name. Well-known guru Eric Lippert once blogged 关于它。
我在这里要问的问题在某种意义上(不)与线程 Circular definition in a constant enum 中提出的问题完全相同。如果你愿意,你可以去给另一个问题投票。
现在是我的问题。考虑这段代码:
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
可以指代 enum
类型,也可以指代具有相同名称的 class 成员.但是上面说的Color Color
规则就是说我们要看成员(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)
}
}
我确信这与常量的值在编译时必须是确定的这一事实有关,但(静态)属性 的值将在 运行-时间。
1) 它不适用于 const
因为它试图同时允许两种定义(枚举类型和 class 成员),所以它试图将自己定义为自身的一个功能。
2) 是无意的吗?有点。这是预期行为的意外后果。
基本上,这是 Microsoft 承认但已归档为“不会修复”的错误,记录在 Connect here。
我在任何地方都找不到 5.0 语言规范(以文章或博客的形式),但如果您有兴趣,可以下载它 here。我们对第 161 页的第 7.6.4 节“成员访问”感兴趣,它是第 7.6.4.1 节,与 OP 链接到的同一节(当时是 7.5.4.1)。
您可以为成员和类型命名完全相同的名称(例如,Color)这一事实是明确允许的,即使您的标识符现在具有两个不同的含义。这是规范的语言:
7.6.4.1 Identical simple names and type names In a member access of the form E.I, if E is a single identifier, and if the meaning of E as a simple-name (§7.6.2) is a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name (§3.8), then both possible meanings of E are permitted. The two possible meanings of E.I are never ambiguous, since I must necessarily be a member of the type E in both cases. In other words, the rule simply permits access to the static members and nested types of E where a compile-time error would otherwise have occurred. For example:
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 的两种可能含义。 E.I 的两种可能含义绝不会含糊不清,因为在这两种情况下 I 都必须是类型 E 的成员。换句话说,该规则只允许访问 E 的静态成员和嵌套类型,否则会发生编译时错误。
当您定义 Color Color = Color.Brown
时,有些事情会发生变化。由于 I (Brown) must 在两种情况下(静态和非静态)都是 E(Color)的成员,因此此规则允许您访问两者,而不是由于当前(非静态)上下文。但是,现在您已经将其中一个上下文(您的非静态上下文)设为常量。因为它允许两者,所以它试图将 Color.Brown
定义为 both 枚举和 class 成员,但是它有一个问题取决于它自己的价值(你例如不能有 const I = I + 1
)。
这是一个错误。我无法在 VS 2015 的 CTP 5 中重现这个问题,我认为这个应该作为 Roslyn 重写的一部分得到修复。然而,下面的评论者指出他们可以在 CTP 6 中重现它。所以我不确定这里发生了什么,至于这个错误是否已被修复。
就个人而言:我不记得在 2010 年首次报道时我是否负责调查这个问题,但由于当时我在圆度检测器上做了很多工作,所以可能性是非常好。
这远不是圆度检测器中存在的唯一错误;如果存在嵌套的泛型类型,而嵌套的泛型类型又具有其类型参数涉及嵌套类型的泛型基类型,它会变得非常混乱。
亚历克斯"won't fix"编了这个我一点也不惊讶;我花了很长时间重写执行 class 循环检测的代码,并且更改被认为风险太大。所有这些工作都交给了 Roslyn。
如果您有兴趣了解 Color Color 绑定代码在 Roslyn 中的工作原理,请查看恰当命名的方法 BindLeftOfPotentialColorColorMemberAccess
-- 我喜欢一些描述性的方法名称 -- 在 Binder_Expressions.cs
.