在C#中,shadowing和overriding之间的区别是什么?
C#中的隐藏和重写之间的区别是什么?
隐藏实际上是VB中的说法,我们在C#中将其称为隐藏。
通常隐藏(VB中的阴影)和重写是由Stormenet以答案的形式展示的。
虚方法被子类重写,并且即使在超类类型或超类内部代码中调用该方法,也会调用子类的替代实现。
然后,通过在子类上定义一个具有相同签名的方法时使用new
关键字来隐藏一个具体方法(未标记为virtual或abstract)。在这种情况下,当在超类类型上调用该方法时,将使用原始实现,新实现仅在子类上可用。
然而,通常被忽视的是也可以隐藏虚方法。
class A { public virtual void DoStuff() { // original implementation } } class B : A { public new void DoStuff() { //new implementation } } B b = new B(); A a = b; b.DoStuff(); //调用新实现 a.DoStuff(); //调用原始实现。
请注意,在上面的示例中,DoStuff变为具体方法,不能被重写。但是,也可以同时使用virtual
和new
关键字。
class A { public virtual void DoStuff() { // original implementation } } class B : A { public new virtual void DoStuff() { //new implementation } } class C : B { public override void DoStuff() { //replacement implementation } } C c = new C(); B b = c; A a = b; c.DoStuff(); //调用替代实现 b.DoStuff(); //调用替代实现 a.DoStuff(); //调用原始实现。
请注意,尽管所有涉及的方法都是虚方法,但C上的重写不会影响A上的虚方法,因为B中的new
隐藏了A的实现。
编辑:这个答案的评论中指出上面的内容可能是危险的或者至少不是特别有用的。我会说是的,它可能是危险的,如果它有用的话,它将会存在。
特别是如果您还更改了可访问性修饰符,可能会遇到各种麻烦。例如:
public class Foo { internal Foo() { } protected virtual string Thing() { return "foo"; } } public class Bar : Foo { internal new string Thing() { return "bar"; } }
对于Bar
的外部继承者来说,Foo
的Thing()实现仍然是可访问和可重写的。根据.NET类型规则,这是合法的和可以解释的,但是相当不直观。
我发布这个答案是为了加深对事物运作方式的理解,而不是建议可以自由使用的技术。
很高兴知道这个。虽然它的使用可能很危险 🙂
所有工具在未正确使用时都可能是危险的。
但是,它的可用性似乎真的值得怀疑!是否有任何“严肃”的开源应用程序使用这个?
可用性?你是指有用性吗?某些边缘情况可能在你需要它们之前似乎是无用的。
似乎只有在使用虚拟和新的时候才会出现阴影。解释只是覆盖行为,因为类调用自己的方法是正常行为,除非它是虚拟的。
在C#中,shadowing和overriding是两种不同的方法来处理继承关系中的方法或属性。shadowing是一种在子类中重新使用同名成员的方式,而overriding是一种改变方法或属性实现细节的方式,但不改变其可访问性和签名。
Shadowing的出现原因是为了解决在子类中需要重新定义父类成员的情况。通过shadowing,在子类中可以重新定义一个与父类同名的成员,从而隐藏父类的成员,使得在子类中可以使用新的实现。
Overriding的出现原因是为了实现多态性。通过overriding,子类可以改变继承自父类的方法或属性的实现细节,以满足自己的需求,同时保留其可访问性和签名,使得子类的对象在调用时可以根据实际类型来执行相应的方法。
解决方法:
1. 对于shadowing,可以在子类中使用关键字"new"来定义一个与父类同名的成员,从而隐藏父类的成员。例如:
class Parent
{
public void Method()
{
Console.WriteLine("Parent Method");
}
}
class Child : Parent
{
public new void Method()
{
Console.WriteLine("Child Method");
}
}
class Program
{
static void Main(string[] args)
{
Parent parent = new Parent();
Child child = new Child();
parent.Method(); // 输出:Parent Method
child.Method(); // 输出:Child Method
Parent childAsParent = new Child();
childAsParent.Method(); // 输出:Parent Method
}
}
2. 对于overriding,需要在父类的方法或属性前添加关键字"virtual",并在子类中使用关键字"override"来重新实现。例如:
class Parent
{
public virtual void Method()
{
Console.WriteLine("Parent Method");
}
}
class Child : Parent
{
public override void Method()
{
Console.WriteLine("Child Method");
}
}
class Program
{
static void Main(string[] args)
{
Parent parent = new Parent();
Child child = new Child();
parent.Method(); // 输出:Parent Method
child.Method(); // 输出:Child Method
Parent childAsParent = new Child();
childAsParent.Method(); // 输出:Child Method
}
}
通过上述方法,我们可以在C#中使用shadowing和overriding来处理继承关系中的方法或属性,以实现不同的需求。
C#中的shadowing和overriding的区别是什么?
在C#中,shadowing和overriding是实现继承的两种方式。shadowing是在派生类中重新定义一个与基类中具有相同名称的成员,而overriding是在派生类中重新定义一个与基类中已有的虚方法具有相同名称和签名的成员。
以下是一个示例代码:
class A { public int Foo() { return 5;} public virtual int Bar() {return 5;} } class B : A{ public new int Foo() { return 1;} //shadow public override int Bar() {return 1;} //override }
当调用这些方法时,输出结果如下:
A clA = new A(); B clB = new B(); Console.WriteLine(clA.Foo()); // 输出 5 Console.WriteLine(clA.Bar()); // 输出 5 Console.WriteLine(clB.Foo()); // 输出 1 Console.WriteLine(clB.Bar()); // 输出 1 // 现在让我们将B类转换为A类 Console.WriteLine(((A)clB).Foo()); // 输出 5 <<<-- shadow Console.WriteLine(((A)clB).Bar()); // 输出 1
如果在代码中使用shadowing,即在派生类中使用与基类相同名称的成员,那么无论对象的真实类型是什么,都会返回基类的值。这可能会导致代码中使用基类而不是派生类的情况。
相反,如果使用overriding,在派生类中重新定义了一个已有的虚方法,那么会根据对象的真实类型来调用相应的方法。
有人可能会问,为什么不直接使用基类而不是派生类的成员呢?这是因为overriding提供了多态性,可以根据对象的真实类型来调用相应的方法,而shadowing只是在继承层次结构中提供了一个不同的实现。
另外,对于overloading的概念,它是指方法具有不同的参数类型签名,从而可以根据参数类型的不同来区分不同的方法。而shadowing可以看作是一个隐藏了基类中虚方法的重载。
如果在派生类中使用public int Foo()而不是public new int Foo(),行为将是相同的,仍然会shadow基类的方法。不过编译器会给出一个警告提示,建议使用new关键字来明确表示是要进行shadowing操作。
以上就是C#中shadowing和overriding的区别以及它们的用法和行为。希望对你有所帮助!