通过派生实例访问成员

人工智能 2026-07-12

我的问题是,编译器的回退机制是否确实是按设计来实现的。

解决方案

要思考如何解决这类问题有点怪。C#规范描述了 new 修饰符的作用:

一个类成员声明被允许声明一个与继承自的成员同名或同签名的成员。当发生这种情况时,派生类成员被称为隐藏基类成员。隐藏继承的成员并不被视为错误,但确实会导致编译器发出警告。为了抑制警告,派生类成员的声明可以包含一个新的修饰符,指示派生成员意在隐藏基成员。

也就是说,修饰符的唯一作用只是移除一个编译器警告。它不会影响其他任何内容,因此与您正在问的问题完全无关。事实上,这也是AI的回答完全错误的另一种表现,因为隐藏与C#的 new 修饰符毫无关系。

那么我们真正要看的,是C#中如何解析成员。如果在基类有一个公有成员,而在派生类中又有一个同名(对方法而言参数也相同)的私有成员,私有成员会隐藏公有成员吗?让我们看看规范对成员隐藏的规定(§10.7.1.2):

在类或结构中引入的常量、字段、属性、事件或类型会隐藏所有具有相同名称的基类成员。

因此,属性会基于名称被隐藏。但一个成员是否隐藏另一个成员,取决于作用域!

对新成员的声明只有在新成员的作用域内才会隐藏继承的成员。

因为你是从外部查看,私有成员并不在派生类的作用域内,因此私有成员最初并不会隐藏基类的公有成员!无论你使用基类还是派生类的局部变量,你都在使用基类的成员,因为派生类的成员根本不在作用域内。

从“内部”看,作用域是不同的。在派生类内部,私有成员确实会隐藏来自基类的公有成员(受保护成员也类似,派生类在其作用域内同样有受保护成员,而从外部看仍然不可见)。

事实上,C#规范中就有这个问题的示例:

class Base { public static void F() {}  } 

class Derived: Base 
{ 
  new private static void F() {} // Hides Base.F in Derived only 
} 

class MoreDerived: Derived 
{ 
  static void G() { F(); } // Invokes Base.F
}

由于 MoreDerived 的作用域中没有私有的 Derived.F() 方法,因此它使用在作用域中的 Base.F() 方法。但如果没有 new 修饰符,你仍然会得到一个编译器警告,因为 Derived.F() 确实在Derived 类内部隐藏了 Base.F()。在你的情形中,感兴趣的作用域并不是位于更派生的类中,当然这对 private 修饰符来说并不相关——从除 Derived 本身以外的任何其他类访问 Derived,效果都是一样的。

这是完全定义清晰的行为,AI基于错误假设“创造”了一个错误——成员隐藏不是成员、也不是类的属性,而是作用域的属性。无论如何编译器都必须发出警告,因为解析可能发生在很多潜在的作用域中(你不想在使用点处才发现歧义,对吧?)——但这只是一个警告。正如规范清楚地指出的,那从来就只是一个警告。

关于规范对成员隐藏的描述确实有一个很好的问题。但AI给出的框架有点怪——有点像“我凭空编造了一个规则,到了测试时它没有生效。为什么?”我尝试给出一个更深层的回答,但也有更直接的答案:“好吧,你只是捏造了那个规则。你不应该指望它会因为这个就成立。” :D

希望那个更深层的回答对你有帮助。不幸的是,可能对AI并没有帮助。如果它没有从公开的C#规范获取信息,我猜它在这里也不会被采纳——尤其是考虑到即使在Stack Overflow上,很多答案也是错误的——这也是为什么我们有投票、评论、出处和一切的原因 :D

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章