什么是暗影?
在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为子例程的地址。
另一方面,当方法被隐藏时,新的地址被添加到子类的方法调用表中。
当打电话给有问题的方法时:
- 方法调用表类的types是获得的,如果我们正在调用基类的引用,那么获得基类方法表,如果我们有一个子类的引用,那么子类方法表就被获得了。
- 在表中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