为什么类成员的名称不能与其中一个嵌套类相同?

Laz*_*zlo 16 c# conflict properties nested-class

或者为什么以下不可能:

class Material
{
    class Keys
    {
        ...
    }

    Material.Keys Keys { get; set; } // Illegal
}
Run Code Online (Sandbox Code Playgroud)

我没有看到任何可能的歧义.按实例访问时,返回属性.静态访问时,返回类.或者我错过了什么?

我不是要求"修复"(我知道我可以用不同的名称来命名,比如MaterialKeys等),但更多的是这个限制背后的技术原因.

Jim*_*hel 14

但想象你有这个:

class Material
{
    class Keys
    {
        ...
    }

    static Material.Keys Keys = new Keys();
}
Run Code Online (Sandbox Code Playgroud)

现在两者都处于"静态"范围.现在,编译器可以在所有情况下消除歧义吗?如果没有,则不允许这样做.

我认为消歧可能适用于静态字段/属性/方法,而不适用于实例成员.或者相反.如果是这种情况,您是否希望语言规范允许实例成员与内部类具有相同的名称,但是不允许它用于静态?那只会令人困惑.

但是,无论如何,让一个成员匹配内部类的名称是相当混乱的.


Eri*_*ert 12

"任何不模糊的东西都应该是合法的"绝对不是C#语言的设计原则.C#语言旨在成为"质量坑"的语言; 也就是说,语言规则应该让你进入一个充满清晰正确代码的坑,你必须努力爬出坑,把它变成错误的代码.在大多数情况下,"任何不模糊的东西应该是合法的"这一观点直接违背了"质量坑"语言的概念.

此外,您需要为不提供功能提供理由的想法是倒退的.我们没有以往任何时候都需要为提供理由不这样做的特征.相反,提出的功能必须通过证明它们的好处超过它们的巨大成本来证明.功能非常昂贵,我们的预算有限; 我们必须只做最好的功能,以便为我们的客户带来好处.

您提出的功能可以轻松生成易碎且令人困惑的代码; 它有助于使C#成为一个"绝望的陷阱"而不是"质量陷阱"的语言.增加脆弱性和混淆语言的功能必须为补偿这些成本带来巨大的好处.您认为此功能为语言证明其成本增加的巨大好处是什么?

如果答案是"没有这样的好处",那么现在你就知道为什么语言没有这个特性:因为它使语言变得更糟,网络.

如果有一个好处,我很高兴考虑它的假设未来版本的语言的优点.

  • 我认为这个功能有好处.可以定义类和该类型成员的类可以实现良好的封装.我确实理解歧义问题,我想知道如何解决这个问题.也许我们生活在更模糊的代码中(虽然这不是C#方式).或者我们在语言中添加一些内容以允许此功能.也许是内部类的特殊语法,允许这样做.我不知道它会是什么,但是可以消除模棱两可的问题. (4认同)
  • 我没有暗示有什么大的好处。我只是想知道语言的语义。显然 StackOverflow 不仅仅是一个“理解的坑”。 (2认同)
  • 方便的用途之一是当您有一个类公开仅属于其上下文的枚举时。例如,假设我们有一个“枚举 ReportType”。现在我可能想要一个名为“enum ReportType”类型的 ReportType 属性。我不想在此类之外混淆该枚举,因为我想将其称为“Foo.ReportType.MyFancyReport”。在创建模型类时,这种情况很常见。 (2认同)
  • @Eric Lippert:好处是您实际上可以将 SQL 实体映射到 CLR 实体,而无需映射器。例如,当表和列名称由有效的 C# 标识符组成时,“带有字段消息 varchar(X) 的表消息”映射到“类消息{ public string message;}”。现在,这是不可能的,您需要重命名表或字段,或者使用会减慢数据获取速度的映射器 - 所有这些都是不好的 - 并且如果您有一个包含许多现有查询/更新的现有数据库/interfaces,重命名字段/表实际上是不可能的。谈论“质量坑”... (2认同)
  • @Eric Lippert:没有某些功能也可能是绝望的深渊。 (2认同)

Tim*_*mwi 5

你说,

\n\n
\n

当被实例访问时,返回该属性。静态访问时,返回类。

\n
\n\n

但如果你说只是Keys在里面的某个地方Material呢?这是静态访问还是实例访问?这是指属性Keys还是嵌套类型Keys?其实是有歧义的。

\n\n

例如,

\n\n
class Material\n{\n    class Keys\n    {\n        public static int Length;\n    }\n\n    string Keys { get; set; }\n\n    public void Process()\n    {\n        // Does this refer to string.Length (via property Keys)\n        // or Material.Keys.Length? It actually refers to both.\n        Console.WriteLine(Keys.Length);\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

正如评论中所指出的,这并不是故事的全部;但几乎。具有以Color该类型命名的属性是有效的Color,并且不会发生冲突:

\n\n
public Color Color { get; set; }\n\nColor.FromName(...)   // refers to static method on the type \xe2\x80\x98Color\xe2\x80\x99\nColor.ToString()      // refers to instance method on the property\xe2\x80\x99s value\n
Run Code Online (Sandbox Code Playgroud)\n\n

但这很容易解决,因为当前范围内的事物胜过更外部范围内的事物:

\n\n
public class MyType { public string FromName(string name) { return null; } }\npublic MyType Color;\n\nColor.FromName(...)   // unambiguously refers to MyType::FromName(string)\n                      // via the property Color\n
Run Code Online (Sandbox Code Playgroud)\n\n

在您的示例 \xe2\x80\x94 中并不那么容易,嵌套类Keys和属性Keys位于同一范围内(具有相同的声明类型)。您如何决定优先考虑哪一个?即使您确实决定给予其中一个优先级,这也只会有一定的用处,因为您仍然只能有两个同名的事物,并且一个必须是静态的,另一个必须是实例。

\n

  • 这不是故事的全部;纯粹通过这个推理,`public Color Color { get; 放; }` 也应该是非法的。 (4认同)
  • “this”关键字可以解决这个问题。当我执行“this.Keys.Length”时,出现歧义异常。 (2认同)