引言:使用Rider开发…

Rider

使用Raider比使用Visual Studio开发流畅一些… 如何下载?www.jetbrains.com的 Tools 下 Rider 进行下载…

JetBrains:Rider、ReSharper、dotPeek
image.pngimage.png
Rider 支持包括 .NET Core 在内的较全面的 .NET 开发,以及 Unity 开发。
.NET Core / ASP.NET Web Application 开发包括:①RestFul API ②.NET Core 网站开发

Q:Rider 是否支持 WinForm 开发?
A:不支持 WinForm,但支持基于 XAML 的 WPF 和 Xamarin
(18)重写与多态 - 图3
Java 常用 Spring + Hibernate + JPA 这一套,它们都能在 .NET Core 找到对应选择。
ASP.NET Core 框架 + Entity Framework Core
.NET Core 自带 Razor engine

Edx Timothy 参与开发的课程

校长关于 ASP.NET Core 开发的一些课程,分别讲 LINQ、Web 开发基础、RestFul API、实战。
未来还将有一门 ASP.NET Core 高级开发和 Authentication & Authorization。
(18)重写与多态 - 图4

DFS 与 BFS

  • DFS:Depth-First-Search 深度优先搜索
  • BFS:Breadth-First Search 广度优先搜索 ```csharp using System; using System.Collections.Generic; using System.Linq;

namespace ConsoleTemp { // 注:为了方便理解,很多变量命名都用的全称 class Program { static void Main(string[] args) { // 生成 [0,10) 的自然数数组,即 0,1,2,3…9 var values = Enumerable.Range(0, 10).ToArray(); var binarySearchTree = GetTree(values, 0, values.Length - 1); DFS(binarySearchTree); Console.WriteLine(“============================”); BFS(binarySearchTree); }

  1. static Node GetTree(int[] values, int lowIndex, int highIndex)
  2. {
  3. if (lowIndex > highIndex) return null;
  4. var middleIndex = lowIndex + (highIndex - lowIndex) / 2;
  5. var node = new Node(values[middleIndex]);
  6. node.Left = GetTree(values, lowIndex, middleIndex - 1);
  7. node.Right = GetTree(values, middleIndex + 1, highIndex);
  8. return node;
  9. }
  10. static void DFS(Node node)
  11. {
  12. if (node == null) return;
  13. DFS(node.Left);
  14. Console.WriteLine(node.Value);
  15. DFS(node.Right);
  16. }
  17. static void BFS(Node root)
  18. {
  19. var q = new Queue<Node>();
  20. q.Enqueue(root);
  21. while (q.Count > 0)
  22. {
  23. var node = q.Dequeue();
  24. Console.WriteLine(node.Value);
  25. if (node.Left != null) q.Enqueue(node.Left);
  26. if (node.Right != null) q.Enqueue(node.Right);
  27. }
  28. }
  29. }
  30. class Node
  31. {
  32. public int Value { get; set; }
  33. public Node Left { get; set; }
  34. public Node Right { get; set; }
  35. public Node(int value)
  36. {
  37. Value = value;
  38. }
  39. }

}

  1. ![](https://cdn.nlark.com/yuque/0/2018/png/101969/1539823542004-c433670b-fe0b-41c6-8071-4a3c580a693b.png?x-oss-process=image%2Fresize%2Cw_232%2Climit_0#crop=0&crop=0&crop=1&crop=1&from=url&id=vqPKa&margin=%5Bobject%20Object%5D&originHeight=338&originWidth=232&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=)
  2. <a name="fedc1897"></a>
  3. ## C# 语言标准文档
  4. C# 5.0 已经成为国际标准 ECMA-334,ECMA-334 的 PDF 比微软自己的标准文档还要权威。<br />C# 6.0 7.0 还在 ECMA 验证中。<br />笔者注:校长还是很注重标准文档,推荐有志于深入 C# 的同学去多翻一翻、读一读。
  5. ---
  6. <a name="LdvYq"></a>
  7. # 重写与多态
  8. 多态是基于重写的
  9. - 继承:向子类中添加父类没有的成员,子类对父类的横向扩展
  10. - 重写:纵向扩展,成员没有增加,但成员的版本增加了
  11. ![image.png](https://cdn.nlark.com/yuque/0/2022/png/26312855/1657335665981-a06307a3-a6d4-4918-9009-02eb14f3d625.png#clientId=u9ba3408c-ecd3-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=276&id=u7d402dfa&margin=%5Bobject%20Object%5D&name=image.png&originHeight=524&originWidth=776&originalType=binary&ratio=1&rotation=0&showTitle=false&size=311917&status=done&style=none&taskId=u0c9ca5b0-c945-4716-9fed-335399735cb&title=&width=408.553955078125)<br />下面开始讲解本节的正式内容:<br />本节内容
  12. - 类的继承
  13. - 类成员的“横向扩展”(成员越来越多)
  14. - 类成员的“纵向扩展”(行为改变,版本增高)
  15. - 类成员的隐藏(不常用)
  16. - 重写与隐藏的发生条件:函数成员,可见,签名一致
  17. - 多态(polymorphism
  18. - 基于重写机制(virtual -> override
  19. - 函数成员的具体行为(版本)由对象决定
  20. - 回顾:C# 语言的变量和对象都是有类型的,所以会有“代差”
  21. <a name="Uynhm"></a>
  22. ## Override 重写(纵向扩展)
  23. 子类对父类成员的重写。因为类成员个数不变,仅更新版本,所以又称为纵向扩展。<br />注:重写时,Car 里面只有一个版本的 Run
  24. 重写需要父类成员标记为 **virtual**,子类成员标记 **override**。<br />注:被标记为 override 的成员,隐含也是 virtual 的,可以继续被重写。
  25. > virtual:可被重写的、名义上的、名存实亡的
  26. ```csharp
  27. class Program
  28. {
  29. static void Main(string[] args){
  30. var car = new Car();
  31. car.Run();//输出 Car is running!
  32. var v = new Vehicle();
  33. v.Run();//输出 I'm running!
  34. var w =new Car();//输出结果具体看实例版本
  35. w.Run();//输出 Car is running!
  36. }
  37. }
  38. class Vehicle {
  39. public virtual void Run(){
  40. Console.WriteLine("I'm running!");
  41. }
  42. }
  43. class Car : Vehicle {
  44. public override void Run(){
  45. Console.WriteLine("Car is running!");
  46. }
  47. }

Hide 子类成员对父类的隐藏(错误用法)

如果子类和父类中函数成员签名相同,但又没标记 virtual 和 override,称为 hide 隐藏。
(18)重写与多态 - 图5image.png

这会导致 Car 类里面有两个版本的 Run 方法,一个是从 Vehicle 继承的 base.Run(),一个是自己声明的 this.Run()。 解释:可以理解为 v 作为 Vehicle 类型,它本来应该顺着继承链往下(一直到 Car)找 Run 的具体实现,但由于 Car 没有 Override,所以它找不下去,只能调用 Vehicle 里面的 Run。

注:

  1. 新手不必过于纠结 Override 和 Hide 的区分、关联。因为原则上是不推荐用 Hide 的。很多时候甚至会视 Hide 为一种错误
  2. Java 里面是天然重写,不必加 virtual 和 override,也没有 Hide 这种情况
  3. Java 里面的 @Override(annotation)只起到辅助检查重写是否有效的功能

    Java内重写: image.png

Polymorphism 多态

C# 支持用父类类型的变量引用子类类型的实例。
函数成员的具体行为(版本)由对象决定。

解释:当调用一个方法成员时,永远能调用到实例的版本(最新的版本)。案例如下: 调用时没有 override 的被 Hide 掉了,最新版本即输出为”Car is running!”。除非如图二所示调用。

image.pngimage.png
回顾:因为 C# 语言的变量和对象都是有类型的,就导致存在变量类型与对象类型不一致的情况,所以会有“代差”。

  1. class Program{
  2. static void Main(string[] args){
  3. Vehicle v = new RaceCar();
  4. v.Run();// Race car is running!
  5. Car c = new RaceCar();
  6. c.Run();// Race car is running!
  7. Console.ReadKey();
  8. }
  9. }
  10. class Vehicle{
  11. public virtual void Run(){
  12. Console.WriteLine("I'm running!");
  13. }
  14. }
  15. class Car : Vehicle{
  16. public override void Run(){
  17. Console.WriteLine("Car is running!");
  18. }
  19. }
  20. class RaceCar : Car{
  21. public override void Run(){
  22. Console.WriteLine("Race car is running!");
  23. }
  24. }

C# vs Python

Python 是对象有类型,变量没有类型的语言,Python 变量的类型永远跟着对象走。 所以在 Python 中即使重写了,也没有多态的效果。
(18)重写与多态 - 图10
PS:

  1. JS 和 Python 类似,也是对象有类型,变量没类型
  2. TypeScript 是基于 JS 的强类型语言,所以 TS 变量是有类型的,存在多态

    重写三条件

    函数成员

    只有函数成员才能重写,最常用的是重写 Methods 和 Properties。
    函数成员的定义:
    (18)重写与多态 - 图11
    重写属性示例:
    image.pngimage.png
    image.pngimage.png
    image.pngimage.png

    可见

    只有对子类可见的父类成员可以重写,具体说就是 protected 和 public。例如子类能继承父类 private 的成员,但无法访问,即不可见、不可重写。
    访问级别的更多内容参考(17)类的声明,继承和访问控制

    签名一致

    方法签名:方法名称 + 类型形参的个数 + 每个形参(从左往右)的类型和种类(值、引用或输出)。
    注:下面要讲接口和抽象类,为了与本节内容混淆,必须把本节彻底消化吸收。