【问题标题】:What is the difference between method hiding and shadowing in C#?C# 中的方法隐藏和阴影有什么区别?
【发布时间】:2012-03-01 16:38:56
【问题描述】:

C# 中的方法隐藏和阴影有什么区别?它们是相同的还是不同的?我们可以称它们为多态(编译时或运行时)吗?

【问题讨论】:

  • 不,这是不同的比较。

标签: c# polymorphism shadowing method-hiding


【解决方案1】:

C#中的方法隐藏和阴影有什么区别?

阴影是另一个常用的隐藏术语。 C# 规范仅使用“隐藏”,但两者都可以接受。

您只调用“方法隐藏”,但除了方法隐藏之外还有其他形式的隐藏。例如:

namespace N
{   
    class D {}
    class C 
    {
        class N
        {
            class D
            {
                 N.D nd; // Which N.D does this refer to?

嵌套类 N 在 D 内部时隐藏了命名空间 N。

我们可以称它们为多态性(编译时或运行时)吗?

方法隐藏可以用于多态性,是的。您甚至可以将方法隐藏与方法覆盖混合使用;通过隐藏旧的虚方法引入新的虚方法是合法的;在这种情况下,选择哪种虚拟方法取决于接收器的编译时运行时类型。这样做非常令人困惑,您应该尽可能避免这样做。

【讨论】:

  • 您说“方法隐藏可用于多态性,是的”。那么是编译时多态还是运行时多态呢?
  • @ShaileshJaiswal:阅读该句子后面的句子。
  • 感谢 Eric 明白了你的意思。我读了这篇文章dotnet-guide.com/what-do-you-mean-by-shadowing-in-dot-net.html。方法隐藏在基类和派生类中可以有不同的签名吗?
  • @ShaileshJaiswal:“新”方法应该具有与其隐藏的方法完全相同的签名;如果没有,那么编译器会给你一个警告,指出“新”是不必要的。
【解决方案2】:

VB.NET 编译器将其称为遮蔽,在 C# 中称为隐藏。在 C# 中将其称为阴影是 VB 的溢出效应。

这是一个编译器警告,它本质上是基类和派生类之间的名称冲突。

我们可以称它们为多态性(编译时或运行时)吗?

它当然不是运行时多态的一种形式。对隐藏或隐藏方法的调用在编译时解决。这使得它通常不会被称为或考虑多态性。

【讨论】:

    【解决方案3】:

    这两个术语在 C# 中的含义相同。

    方法隐藏 == 阴影。

    您可以将其用作多态的一种形式 - 当您不希望基类方法通过继承类可见/可用时。

    阴影方法与基类完全分离——它是一种新方法。使用术语隐藏是因为它具有与基类相同的签名并且正在“隐藏”它 - 它破坏了继承链。

    【讨论】:

    • 为了进一步澄清,这种类型的方法调用是在编译时确定的(静态绑定)。如果您想要运行时评估或动态绑定,您必须使用virtual(和子类中的override)。我认为编译时评估根本不是多态代码,但我相信其他人有不同的看法。
    • @Matthew - virtual override.
    【解决方案4】:

    C# (new modifier) 的名称隐藏在 VB.NET (keyword Shadows) 中称为遮蔽。

    这可以被认为是多态性,仅在覆盖是“多态性”的意义上,即静态或编译时。它不是调用虚函数的经典意义上的多态性。

    【讨论】:

      【解决方案5】:

      它们只是同一事物的两个不同词,但在您最常使用它们的上下文中有所不同。通常,所谓的“隐藏”与多态性有关,而所谓的“阴影”则无关。

      在 C# 用语中,当您说“隐藏”时,您通常是在谈论继承,其中派生程度更高的方法从正常的继承方法调用链中“隐藏”基类方法。

      当您说“影子”时,您通常是在谈论作用域:内部作用域中的标识符正在“隐藏”更高作用域中的标识符。在其他语言中,C# 中所谓的“隐藏”有时也称为“阴影”。

      两者都是编译时概念;当编译器去绑定它时,它们描述了给定标识符在给定上下文中引用的对象。

      public class A
      {
        public int B;
        public void C()
        {
          return this.B;
        }
      }
      
      public class D : A
      {
        public int X;
      
        public new void C()
        {
          var X = 1.0m;
          return X;
        }
      }
      

      方法D.C()“隐藏”方法A.C();通常,对D.C() 的调用总是会调用基类A.C() 方法,因为它不是virtual。我们不希望这样;我们想要D.C()。显然这是你应该尽量避免的事情,因为它会让人困惑,尤其是当你开始将你的 D 转换为 A 时,但如果你需要它就存在。另外,请注意,方法隐藏是自动的:如果此处没有 new 关键字,D.C() 仍会隐藏 A.C(),但我们会收到警告,因为 通常 这不是您想要的。 new 关键字清楚地表明这确实是我们想要的。

      局部变量XD.C()阴影类成员D.X仅在D.C()范围内。在这种情况下,范围内有两件事可以合法地称为X,编译器需要规则来告诉它你的意思是哪一个。 “更本地化”X 掩盖了“更本地化”D.X,这就是我们得到的。

      【讨论】:

        猜你喜欢
        • 2022-01-20
        • 1970-01-01
        • 1970-01-01
        • 2018-06-26
        • 2012-12-04
        • 1970-01-01
        • 2012-08-24
        • 1970-01-01
        • 2012-01-24
        相关资源
        最近更新 更多