什么是暗影?

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

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

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 。 覆盖使用覆盖关键字。 使用新的关键字进行遮蔽。

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

 'test.B.Foo()' hides inherited member 'test.A.Foo()'. Use the new keyword if hiding was intended. 
  • 覆盖:重新定义基类上的现有方法
  • 阴影:创build一个全新的方法,在基类中使用相同的签名

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

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

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

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

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

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

我有两个不同的select,我希望如何实施。 默认行为是调用A的版本M.(这与您将“ new ”关键字应用于BM()的行为相同。

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

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

阴影是在一个子类中用一个新的定义隐藏一个基类方法。

隐藏和重写的区别在于方法被调用的方式。

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

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

当打电话给有问题的方法时:

  1. 方法调用表类的types是获得的,如果我们正在调用基类的引用,那么获得基类方法表,如果我们有一个子类的引用,那么子类方法表就被获得了。
  2. 在表中search该方法,如果find则调用发生,否则search基类方法表。

如果我们调用引用子类的方法,那么行为是相同的,如果方法被覆盖,方法地址将在基类中find,如果方法被隐藏,方法地址将在子类,因为它已经被发现,基类表将不被search。

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

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

扩大肯特的正确答案

在明确何时调用哪种方法的时候,我喜欢想象阴影与重写以下内容

  • 隐藏:调用的方法取决于调用时引用的types
  • 覆盖:调用的方法取决于调用时的对象types。

这是关于阴影的MSDN文章 。 语言的例子是在Visual Basic中(不幸的是,在MSDN上没有相应的C#页面),但是它总体上处理了这些概念,希望能帮助你理解。

编辑:似乎有一个关于阴影的C#文章 ,除了它被称为隐藏在C#中。 另外, 这个页面提供了一个很好的概述。

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

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

 Base B=new Child() 

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

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

影子不是我会担心的理解或实施,除非它真正“适合”的问题。 我已经看到它使用不当,导致怪异的逻辑错误比正确使用更频繁。 我认为,最主要的原因是程序员忘记在方法签名中覆盖,然后编译器警告会提示新的关键字。 我一直觉得应该推荐使用覆盖。

  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