在C#中,术语阴影是什么意思?我看过this link,但没有完全理解它。
答案 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)
阴影包括在子类中隐藏带有新定义的基类方法。
隐藏和覆盖之间的区别与调用方法的方式有关。
这样,当重写虚方法时,基类的方法调用表的调用地址将替换为子例程的地址。
另一方面,当隐藏方法时,会将新地址添加到子类的方法调用表中。
当对相关方法进行调用时:
如果我们通过引用子类调用方法然后行为是相同的,如果方法已被重写,方法地址将在基类中找到,如果方法被隐藏,方法地址将是在子类中找到,并且因为已经找到它,所以不会搜索基类表。
如果我们通过引用基类来调用该方法,那么行为会发生变化。覆盖时,当方法地址覆盖基类条目时,即使持有对基类的引用,我们也会调用子方法。使用阴影时,基类方法表(它是我们持有对基类的引用时唯一可见的)包含虚方法地址,因此将调用基类方法。
一般来说,阴影是一个坏主意,因为它会根据我们对它的引用引入实例行为的差异。
答案 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)
覆盖:实现相同名称和完全相同的参数 在子类中有所不同。
阴影:相同的名称和完全相同的参数,在子类中的实现方式不同。
答案 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