什么是影子?

时间:2009-03-23 15:16:18

标签: c# polymorphism shadowing

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

11 个答案:

答案 0 :(得分:45)

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

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。覆盖使用覆盖关键字。使用关键字进行隐藏。

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

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

答案 1 :(得分:32)

  • 覆盖:重新定义基类上的现有方法
  • 阴影:创建一个与基类具有相同签名的全新方法

答案 2 :(得分:20)

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

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()时的行为相同。)

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

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

答案 3 :(得分:10)

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

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

这样,当重写虚方法时,基类的方法调用表的调用地址将替换为子例程的地址。

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

当对相关方法进行调用时:

  1. 获取方法调用表类类型,如果我们使用对基类的引用进行调用,则获取基类方法表,如果我们有对子类的引用,则获取子类方法表
  2. 在表中搜索该方法,如果找到则进行调用,否则搜索基类方法表。
  3. 如果我们通过引用子类调用方法然后行为是相同的,如果方法已被重写,方法地址将在基类中找到,如果方法被隐藏,方法地址将是在子类中找到,并且因为已经找到它,所以不会搜索基类表。

    如果我们通过引用基类来调用该方法,那么行为会发生变化。覆盖时,当方法地址覆盖基类条目时,即使持有对基类的引用,我们也会调用子方法。使用阴影时,基类方法表(它是我们持有对基类的引用时唯一可见的)包含虚方法地址,因此将调用基类方法。

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

答案 4 :(得分:8)

扩展肯特的正确答案

当消除何时调用哪种方法的歧义时,我喜欢考虑阴影与覆盖以下

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

答案 5 :(得分:3)

这是关于阴影的MSDN article。语言示例在Visual Basic中(遗憾的是MSDN上没有等效的C#页面),但它通常涉及概念,希望无论如何都应该帮助您理解。

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

答案 6 :(得分:2)

如果要隐藏基类方法,请在base [base method in base]

中使用override

如果你想隐藏Child类方法,请在base中使用new [base中的非虚方法] - > shadow

Base B=new Child()

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

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

答案 7 :(得分:0)

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

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

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

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

答案 8 :(得分:0)

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

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;
        }
    }

答案 9 :(得分:-3)

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

答案 10 :(得分:-4)

 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