建议94:区别对待override和new

override和new使类型体系应为继承而呈现出多态性。多态要求子类具有与基类同名的方法,override和new的作用就是:

  • 如果子类中的方法前面带有new关键字,则该法被定义为独立于基类的方法。
  • 如果子类中的方法前面带有override关键字,则子类的对象将调用该方法。而不调用基类的方法。

我们来看一个继承体系:

  1. public class Shape
  2. {
  3. public virtual void MethodVirtual()
  4. {
  5. Console.WriteLine("base MethodVirtual call");
  6. }
  7.  
  8. public void Method()
  9. {
  10. Console.WriteLine("base Method call");
  11. }
  12. }
  13.  
  14. class Circle : Shape
  15. {
  16. public override void MethodVirtual()
  17. {
  18. Console.WriteLine("circle override MethodVirtual");
  19. }
  20. }
  21.  
  22. class Rectangle : Shape
  23. {
  24.  
  25. }
  26.  
  27. class Triangle : Shape
  28. {
  29. public new void MethodVirtual()
  30. {
  31. Console.WriteLine("triangle new MethodVirtual");
  32. }
  33.  
  34. public new void Method()
  35. {
  36. Console.WriteLine("triangle new Method");
  37. }
  38. }
  39.  
  40. class Diamond : Shape
  41. {
  42. public void MethodVirtual()
  43. {
  44. Console.WriteLine("Diamond default MethodVirtual");
  45. }
  46.  
  47. public void Method()
  48. {
  49. Console.WriteLine("Diamond default Method");
  50. }
  51. }

Shape是所有子类的基类。

Circle类override父类的MethodVirtual,所以即使子类转型为Shape,调用的还是子类方法:

  1. Shape s = new Circle();
  2. s.MethodVirtual();
  3. s.Method();

输出为:

circle override MethodVirtual
base Method call

  1. Circle s = new Circle();
  2. s.MethodVirtual();
  3. s.Method();

输出也为:

circle override MethodVirtual
base Method call

类型Rectangle没有对基类做任何处理,所以无论是否转型为Shape,调用的都是基类Shape的方法。
类型Triangle将基类Shape的virtual方法和非virtual方法都new了一般,所以第一种方法为:

  1. Shape s = new Triangle();
  2. s.MethodVirtual();
  3. s.Method();

因为子类应经new了父类的方法,故子类方法和基类方法完全没有关系了,只要s被转型为Shape,针对s调用搞得都是父类方法。

  1. Triangle triangle = new Triangle();
  2. triangle.MethodVirtual();
  3. triangle.Method();

调用的都是子类方法,输出为:

triangle new MethodVirtual
triangle new Method

类型Diamond包含了两个和基类一模一样的方法,并且没有额外的修饰符。这在编译器中会提出警示。但是如果选择忽略这些警示,程序还是一样可以运行。

  1. Shape s=new Diamond();
  2. s.MethodVirtual();
  3. s.Method();

编译器会默认new的效果,所以输出和显示设置为new时一样。

输出为:

base MethodVirtual call
base Method call

  1. Diamond s = new Diamond();
  2. s.MethodVirtual();
  3. s.Method();

输出为:

Diamond default MethodVirtual
Diamond default Method
最后给一个综合示例:

  1. static void Main(string[] args)
  2. {
  3. TestShape();
  4. TestDerive();
  5. TestDerive2();
  6. }
  7.  
  8. private static void TestShape()
  9. {
  10. Console.WriteLine("TestShape\tStart");
  11. List<Shape> shapes = new List<Shape>();
  12. shapes.Add(new Circle());
  13. shapes.Add(new Rectangle());
  14. shapes.Add(new Triangle());
  15. shapes.Add(new Diamond());
  16. foreach (Shape s in shapes)
  17. {
  18. s.MethodVirtual();
  19. s.Method();
  20. }
  21. Console.WriteLine("TestShape\tEnd\n");
  22. }
  23.  
  24. private static void TestDerive()
  25. {
  26. Console.WriteLine("TestDerive\tStart");
  27. Circle circle = new Circle();
  28. Rectangle rectangle = new Rectangle();
  29. Triangle triangel = new Triangle();
  30. Diamond diamond = new Diamond();
  31. circle.MethodVirtual();
  32. circle.Method();
  33. rectangle.MethodVirtual();
  34. rectangle.Method();
  35. triangel.MethodVirtual();
  36. triangel.Method();
  37. diamond.MethodVirtual();
  38. diamond.Method();
  39. Console.WriteLine("TestShape\tEnd\n");
  40. }
  41.  
  42. private static void TestDerive2()
  43. {
  44. Console.WriteLine("TestDerive2\tStart");
  45. Circle circle = new Circle();
  46. PrintShape(circle);
  47. Rectangle rectangle = new Rectangle();
  48. PrintShape(rectangle);
  49. Triangle triangel = new Triangle();
  50. PrintShape(triangel);
  51. Diamond diamond = new Diamond();
  52. PrintShape(diamond);
  53. Console.WriteLine("TestDerive2\tEnd\n");
  54. }
  55.  
  56. static void PrintShape(Shape sharpe)
  57. {
  58. sharpe.MethodVirtual();
  59. sharpe.Method();
  60. }

输出为:

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个建议》陆敏技

编写高质量代码改善C#程序的157个建议——建议94:区别对待override和new的更多相关文章

  1. 编写高质量代码改善C#程序的157个建议[1-3]

    原文:编写高质量代码改善C#程序的157个建议[1-3] 前言 本文主要来学习记录前三个建议. 建议1.正确操作字符串 建议2.使用默认转型方法 建议3.区别对待强制转换与as和is 其中有很多需要理 ...

  2. 读书--编写高质量代码 改善C#程序的157个建议

    最近读了陆敏技写的一本书<<编写高质量代码  改善C#程序的157个建议>>书写的很好.我还看了他的博客http://www.cnblogs.com/luminji . 前面部 ...

  3. 编写高质量代码改善C#程序的157个建议——建议157:从写第一个界面开始,就进行自动化测试

    建议157:从写第一个界面开始,就进行自动化测试 如果说单元测试是白盒测试,那么自动化测试就是黑盒测试.黑盒测试要求捕捉界面上的控件句柄,并对其进行编码,以达到模拟人工操作的目的.具体的自动化测试请学 ...

  4. 编写高质量代码改善C#程序的157个建议——建议156:利用特性为应用程序提供多个版本

    建议156:利用特性为应用程序提供多个版本 基于如下理由,需要为应用程序提供多个版本: 应用程序有体验版和完整功能版. 应用程序在迭代过程中需要屏蔽一些不成熟的功能. 假设我们的应用程序共有两类功能: ...

  5. 编写高质量代码改善C#程序的157个建议——建议155:随生产代码一起提交单元测试代码

    建议155:随生产代码一起提交单元测试代码 首先提出一个问题:我们害怕修改代码吗?是否曾经无数次面对乱糟糟的代码,下决心进行重构,然后在一个月后的某个周一,却收到来自测试版的报告:新的版本,没有之前的 ...

  6. 编写高质量代码改善C#程序的157个建议——建议154:不要过度设计,在敏捷中体会重构的乐趣

    建议154:不要过度设计,在敏捷中体会重构的乐趣 有时候,我们不得不随时更改软件的设计: 如果项目是针对某个大型机构的,不同级别的软件使用者,会提出不同的需求,或者随着关键岗位人员的更替,需求也会随个 ...

  7. 编写高质量代码改善C#程序的157个建议——建议153:若抛出异常,则必须要注释

    建议153:若抛出异常,则必须要注释 有一种必须加注释的场景,即使异常.如果API抛出异常,则必须给出注释.调用者必须通过注释才能知道如何处理那些专有的异常.通常,即便良好的命名也不可能告诉我们方法会 ...

  8. 编写高质量代码改善C#程序的157个建议——建议152:最少,甚至是不要注释

    建议152:最少,甚至是不要注释 以往,我们在代码中不写上几行注释,就会被认为是钟不负责任的态度.现在,这种观点正在改变.试想,如果我们所有的命名全部采用有意义的单词或词组,注释还有多少存在的价值. ...

  9. 编写高质量代码改善C#程序的157个建议——建议151:使用事件访问器替换公开的事件成员变量

    建议151:使用事件访问器替换公开的事件成员变量 事件访问器包含两部分内容:添加访问器和删除访问器.如果涉及公开的事件字段,应该始终使用事件访问器.代码如下所示: class SampleClass ...

  10. 编写高质量代码改善C#程序的157个建议——建议150:使用匿名方法、Lambda表达式代替方法

    建议150:使用匿名方法.Lambda表达式代替方法 方法体如果过小(如小于3行),专门为此定义一个方法就会显得过于繁琐.比如: static void SampeMethod() { List< ...

随机推荐

  1. 5月12日上课笔记-js 弹出框、函数、程序调试、基本事件、浏览器对象模型

    一.弹出框 a.提示框 alert(); b.输入框 prompt(); c.确认框 confirm(); var flag= confirm("确认删除吗?"); 二.js程序调 ...

  2. c++ 双向链表操作总结

    第一.包含DoubleLinkNode 模板类和DoubleLinkList 模板类 #pragma once #include<iostream> using namespace std ...

  3. nova volume-create的使用

    处理cinder可以直接创建volume外,nova也是可以的 如: 可以看出创建一个名字为volume2的卷,大小为10G 把创建好的volume2卷直接挂在vm虚拟机上 如:先查看计算节点有几个v ...

  4. thrift协议的服务进压力测试

    Thrift vs  Grpc内容如下链接 http://blog.csdn.net/dazheng/article/details/48830511 背景:Facebook 开发的远程服务调用框架 ...

  5. linux命令日志处理

    刘超 2018/10/8 10:32:43 zcat bi_www_activity_2018100*.log.gz |grep --color '多方电话h5_' | awk -F'|' '{pri ...

  6. vs2010 安装 Ajax Control Toolkit

    Ajax Control Toolkit 7.1005.0 The Ajax Control Toolkit contains a rich set of controls that you can ...

  7. ASU一位图形学老师推荐的book list

    http://peterwonka.net/Documentation/BooksToRead.htm 包括数学.图形学.OpenGL等资料

  8. 无法添加数据连接。Could not load file or assembly 'Microsoft.SqlServer.Management.Sdk.Sfc, Version=11.0.0.0

    无法添加数据连接.Could not load file or assembly 'Microsoft.SqlServer.Management.Sdk.Sfc, Version=11.0.0.0 V ...

  9. Halcon学习之三:有关图像通道的函数(R是三通道,B是1通道,G二通道),排列顺序BGR

    黑白摄像机会返回每个像素所对应的能量采用结果,这些结果组成了一幅单通道灰度值图像,而对于RGB彩色摄像机,它将返回每个像素所对应的三个采样结果,也就是一幅三通道图像.下面这些是与图像通道有关的函数: ...

  10. [ 原创 ] Linux下查找指定类型文件以及删除

    find ./ -name "*.lok"   // 查找文件find ./ -name "*.lok" |xargs rm -fr  // 查找文件并删除