【问题标题】:What is Shadowing?什么是阴影?
【发布时间】:2010-10-14 23:58:01
【问题描述】:

在 C# 中,术语 shadowing 是什么意思?我读过this link,但没有完全理解。

【问题讨论】:

  • 不是每个人都以完全相同的方式解释事情吗?学校里有没有你认为比其他人更好的老师?
  • 需要注意的是,阴影是一个VB术语——C#称之为隐藏。
  • 我一直听说它在 JS、C、Java 中称为阴影
  • 这是一个相当不错的视频。 youtube.com/watch?v=xmjOPCnSE30

标签: c# polymorphism shadowing


【解决方案1】:

阴影隐藏基类中的方法。使用您链接的问题中的示例:

class A 
{
   public int Foo(){ return 5;}
   public virtual int Bar(){return 5;}
}
class B : A
{
   public new int Foo() { return 1;}
   public override int Bar() {return 1;}
}

B 覆盖虚拟方法Bar。它隐藏(阴影)非虚拟方法Foo。覆盖使用 override 关键字。使用 new 关键字完成阴影。

在上面的代码中,如果在B 类中定义Foo 方法时没有使用new 关键字,则会收到以下编译器警告:

'test.B.Foo()' hides inherited member 'test.A.Foo()'. Use the new keyword if hiding was intended.

【讨论】:

  • 这个的功能目的是什么?比如你为什么要隐藏一些东西而不是覆盖它?
  • @sab669:假设您想“覆盖”一个非虚拟方法。您实际上无法覆盖它,因此您可以隐藏它。这不是一个完美的解决方案,因为它在所有情况下都不像重写的虚拟方法,但是当从派生类调用时,它会按预期工作。您想要这样做的情况相对较少,但是当您需要它时,您确实需要它。
  • 啊,所以它只是作为“那个方法不是虚拟的,出于某种原因我不能让它成为虚拟的,所以必须做新的”的那种东西?
  • @sab669:这是一种用途。有关更多信息,请参阅 stackoverflow.com/questions/1193848/…stackoverflow.com/questions/14461725/…
【解决方案2】:
  • 覆盖:在基类上重新定义现有方法
  • 阴影:创建一个全新的方法,其签名与基类中的方法相同

【讨论】:

  • 新方法 - 使用相同的签名还是?
  • 请注意,使用阴影可以更改返回类型。
【解决方案3】:

假设我有一个实现虚方法的基类:

public class A
{
    public virtual void M() { Console.WriteLine("In A.M()."); }
}

我还有一个派生类,它也定义了一个方法 M:

public class B : A
{
    // could be either "new" or "override", "new" is default
    public void M() { Console.WriteLine("In B.M()."); }
}

现在,假设我写了一个这样的程序:

A alpha = new B(); // it's really a B but I cast it to an A
alpha.M();

对于我希望如何实现它,我有两种不同的选择。默认行为是调用 A 的 M 版本。(这与将“new”关键字应用于B.M() 时的行为相同。)

当我们有一个同名但从基类调用时行为不同的方法时,这称为“阴影”。

或者,我们可以在B.M() 上指定“override”。在这种情况下,alpha.M() 会调用 B 的 M 版本。

【讨论】:

    【解决方案4】:

    阴影包括在子类中隐藏具有新定义的基类方法。

    隐藏和覆盖之间的区别与调用方法的方式有关。

    这样,当一个虚方法被覆盖时,基类的方法调用表的调用地址被替换为子例程的地址。

    另一方面,当一个方法被隐藏时,一个新的地址被添加到子类的方法调用表中。

    当调用相关方法时:

    1. 获取方法调用表类类型,如果引用基类调用则获取基类方法表,如果引用子类则获取子类方法表.
    2. 在表中搜索方法,如果找到则调用,否则搜索基类方法表。

    如果我们通过引用子类来调用方法,那么行为是相同的,如果方法已被覆盖,则方法地址将在基类中找到,如果方法被隐藏,方法地址将为在子类上找到了,既然已经找到了,就不会去查找基类表了。

    如果我们使用对基类的引用来调用方法,那么行为就会改变。重写时,由于方法地址覆盖了基类条目,我们将调用子方法,即使在持有对基类的引用时也是如此。使用阴影,基类方法表(这是唯一可见的,因为我们持有对基类的引用)包含虚拟方法地址,因此将调用基类方法。

    一般来说,阴影是一个坏主意,因为它会根据我们对它的引用而对实例的行为产生差异。

    【讨论】:

      【解决方案5】:

      扩大肯特的正确答案

      在明确何时调用哪个方法时,我喜欢考虑使用以下方法进行遮蔽与覆盖

      • 阴影:调用的方法取决于调用点的引用类型
      • 覆盖:调用的方法取决于调用时对象的类型。

      【讨论】:

        【解决方案6】:

        这是关于Shadowing 的MSDN article。语言示例在 Visual Basic 中(不幸的是,MSDN 上没有等效的 C# 页面),但它一般处理概念,希望无论如何都能帮助您理解。

        编辑:似乎有一个 C# article 用于阴影,除了它在 C# 中称为 hiding。此外,this page 提供了很好的概述。

        【讨论】:

        【解决方案7】:

        如果要隐藏基类方法,请在基类中使用 override [基类中的虚拟方法]

        如果要隐藏子类方法,使用new in base [nonvirtual method in base]->shadow

        Base B=new Child()
        

        B.VirtualMethod() -> 调用子类方法

        B.NonVirtualMethod() -> 调用基类方法

        【讨论】:

          【解决方案8】:

          覆盖:同名和完全相同的参数,已实现 在子类中有所不同。

          • 如果被视为 DerivedClass 或 BaseClass,则使用派生方法。

          阴影:名称相同,参数完全相同,在子类中实现方式不同。

          • 如果被视为 DerivedClass,则使用派生方法。
          • 如果被视为 BaseClass,则使用基方法。

          【讨论】:

            【解决方案9】:

            希望这个简短的解释有所帮助。

            Shadowing - 替换父类的完整元素

            class InventoryAndSales
            {
                public int InvoiceNumber { get; set; }
            }
            
            //if someone calls for this class then the InvoiceNumber type is now object 
            class NewInventoryAndSales : InventoryAndSales
            {
                public new object InvoiceNumber { get; set; }
            }
            



            Overriding - 仅替换实现。它不会替换它不会替换的数据类型,例如您有一个变量,它不会将其转换为方法,因此如果有方法,它将使用该方法并仅更改实现

             class InventoryAndSales
                {
                    public virtual int GetTotalSales(int a, int b)
                    {
                        return a + b;
                    }
                }
            
            
                class NewInventoryAndSales : InventoryAndSales
                {
                    //it replaces the implementation in parent class
                    public override int GetTotalSales(int a, int b)
                    {
                        return a * b;
                    }
                }
            

            【讨论】:

              【解决方案10】:

              阴影不是我担心理解或实施的事情,除非它非常“适合”问题。我已经看到它使用不当并且比正确使用更频繁地导致奇怪的逻辑错误。我认为,最大的原因是当程序员忘记将覆盖放在方法签名中时,编译器警告会建议使用 new 关键字。我一直觉得应该推荐使用 override。

              【讨论】:

              • 这感觉像是一条评论。
              【解决方案11】:
               private static int x = 10;
              
              
              static void Main(string[] args)
                  { int x = 20;
                      if (Program.x == 10)
                      {
                          Console.WriteLine(Program.x);
                      }
                      Console.WriteLine(x);}
              

              输出:

              10 20

              【讨论】:

              • 这不能回答问题
              猜你喜欢
              • 1970-01-01
              • 2020-08-22
              • 2016-08-22
              • 2016-12-09
              • 2010-11-08
              • 2015-07-23
              • 2022-01-27
              • 2013-02-04
              相关资源
              最近更新 更多