建議94:區別對待override和new
override和new使類型體系應為繼承而呈現出多態性。多態要求子類具有與基類同名的方法,override和new的作用就是:
我們來看一個繼承體系:
public class Shape { public virtual void MethodVirtual() { Console.WriteLine("base MethodVirtual call"); } public void Method() { Console.WriteLine("base Method call"); } } class Circle : Shape { public override void MethodVirtual() { Console.WriteLine("circle override MethodVirtual"); } } class Rectangle : Shape { } class Triangle : Shape { public new void MethodVirtual() { Console.WriteLine("triangle new MethodVirtual"); } public new void Method() { Console.WriteLine("triangle new Method"); } } class Diamond : Shape { public void MethodVirtual() { Console.WriteLine("Diamond default MethodVirtual"); } public void Method() { Console.WriteLine("Diamond default Method"); } }
Shape是所有子類的基類。
Circle類override父類的MethodVirtual,所以即使子類轉型為Shape,調用的還是子類方法:
Shape s = new Circle(); s.MethodVirtual(); s.Method();
輸出為:
circle override MethodVirtual
base Method call
Circle s = new Circle(); s.MethodVirtual(); s.Method();
輸出也為:
circle override MethodVirtual
base Method call
類型Rectangle沒有對基類做任何處理,所以無論是否轉型為Shape,調用的都是基類Shape的方法。
類型Triangle將基類Shape的virtual方法和非virtual方法都new了一般,所以第一種方法為:
Shape s = new Triangle(); s.MethodVirtual(); s.Method();
因為子類應經new了父類的方法,故子類方法和基類方法完全沒有關系了,只要s被轉型為Shape,針對s調用搞得都是父類方法。
Triangle triangle = new Triangle(); triangle.MethodVirtual(); triangle.Method();
調用的都是子類方法,輸出為:
triangle new MethodVirtual
triangle new Method
類型Diamond包含了兩個和基類一模一樣的方法,並且沒有額外的修飾符。這在編譯器中會提出警示。但是如果選擇忽略這些警示,程序還是一樣可以運行。
Shape s=new Diamond(); s.MethodVirtual(); s.Method();
編譯器會默認new的效果,所以輸出和顯示設置為new時一樣。
輸出為:
base MethodVirtual call
base Method call
Diamond s = new Diamond(); s.MethodVirtual(); s.Method();
輸出為:
Diamond default MethodVirtual
Diamond default Method
最後給一個綜合示例:
static void Main(string[] args) { TestShape(); TestDerive(); TestDerive2(); } private static void TestShape() { Console.WriteLine("TestShape\tStart"); List<Shape> shapes = new List<Shape>(); shapes.Add(new Circle()); shapes.Add(new Rectangle()); shapes.Add(new Triangle()); shapes.Add(new Diamond()); foreach (Shape s in shapes) { s.MethodVirtual(); s.Method(); } Console.WriteLine("TestShape\tEnd\n"); } private static void TestDerive() { Console.WriteLine("TestDerive\tStart"); Circle circle = new Circle(); Rectangle rectangle = new Rectangle(); Triangle triangel = new Triangle(); Diamond diamond = new Diamond(); circle.MethodVirtual(); circle.Method(); rectangle.MethodVirtual(); rectangle.Method(); triangel.MethodVirtual(); triangel.Method(); diamond.MethodVirtual(); diamond.Method(); Console.WriteLine("TestShape\tEnd\n"); } private static void TestDerive2() { Console.WriteLine("TestDerive2\tStart"); Circle circle = new Circle(); PrintShape(circle); Rectangle rectangle = new Rectangle(); PrintShape(rectangle); Triangle triangel = new Triangle(); PrintShape(triangel); Diamond diamond = new Diamond(); PrintShape(diamond); Console.WriteLine("TestDerive2\tEnd\n"); } static void PrintShape(Shape sharpe) { sharpe.MethodVirtual(); sharpe.Method(); }
輸出為:
TestShape Start
circle override MethodVirtual
base Method call
base MethodVirtual call
base Method call
base MethodVirtual call
base Method call
base MethodVirtual call
base Method call
TestShape End
TestDerive Start
circle override MethodVirtual
base Method call
base MethodVirtual call
base Method call
triangle new MethodVirtual
triangle new Method
Diamond default MethodVirtual
Diamond default Method
TestShape End
TestDerive2 Start
circle override MethodVirtual
base Method call
base MethodVirtual call
base Method call
base MethodVirtual call
base Method call
base MethodVirtual call
base Method call
TestDerive2 End
轉自:《編寫高質量代碼改善C#程序的157個建議》陸敏技