题 什么是影子?


在C#中,术语是什么 阴影 意思?我读过了 这个链接 但并没有完全理解它。


34
2018-03-23 15:16


起源


不是每个人都以完全相同的方式解释事物吗?在学校里是不是有些老师认为哪个比其他人好?
应该注意的是,阴影是一个VB术语--C#称之为隐藏。 - Adam Lassek
在JS,C,Java中,我总是听到它称之为阴影 - Juan Mendes
这是一个非常好的视频。 youtube.com/watch?v=xmjOPCnSE30 - Chris Lees


答案:


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

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,你会得到这个编译器警告:

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

45
2018-03-23 15:25



这是什么功能目的?就像为什么你会隐藏某些东西而不是覆盖它? - sab669
@ sab669:想象一下,你想“覆盖”一个非虚方法。你实际上无法覆盖它,所以你要遮蔽它。它不是一个完美的解决方案,因为它在所有情况下都不像重写的虚拟方法,但是当从派生类调用时,它将按预期工作。您想要这样做是相对罕见的,但是当您需要它时,您真的需要它。 - Jim Mischel
啊,所以它只是作为一种存在而存在“那种方法不是虚拟的,出于某种原因我不能使它成为虚拟的,所以新的必须做的”那种事情? - sab669
@ sab669:这是一个用途。看到 stackoverflow.com/questions/1193848/... 和 stackoverflow.com/questions/14461725/... 了解更多信息。 - Jim Mischel


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

32
2018-03-23 15:19



新方法 - 具有相同的签名或? - User
+1很好地总结了! - Csharp
请注意,使用阴影可以更改返回类型。 - Dave Cousineau


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

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.


20
2018-03-23 15:24





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

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

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

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

当调用相关方法时:

  1. 获取方法调用表类类型,如果我们使用对基类的引用进行调用,则获取基类方法表,如果我们有对子类的引用,则获取子类方法表。
  2. 在表中搜索该方法,如果找到则进行调用,否则搜索基类方法表。

如果我们通过引用子类来调用该方法,那么行为是相同的,如果方法已被重写,则方法地址将在基类中找到,如果方法被隐藏,则方法地址将在子类,并且因为已经找到它,所以不会搜索基类表。

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

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


10
2018-03-23 15:39





扩展肯特的正确答案

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

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

8
2018-03-23 15:55





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

编辑: 好像在那里  一个 C#文章 关于阴影,除了它被称为  在C#中。也, 这一页 提供了很好的概述。


3
2018-03-23 15:23



那是因为它被称为隐藏在C#中: msdn.microsoft.com/en-us/library/aa691133(VS.71).aspx - Adam Lassek
啊,那可以解释。 - Noldorin


如果要隐藏Base类方法,请在base [base method in base]中使用override

如果要隐藏Child类方法,请在base [base in base] - > shadow中使用new

Base B=new Child()

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

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


2
2018-04-11 06:49