C#的一些基础内容

 1.  c#时间格式转换汉字大写 比如: 2011年6月4日 转换成 二零一一年六月四日
 
View Code
 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5            
 6             //c#时间格式转换汉字大写 比如: 2011年6月4日 转换成 二零一一年六月四日
 7             string date = "2011年6月4日";
 8 
 9             Console.WriteLine(Change(date));
10 
11             Console.Read();
12 
13         }
14         static string Change(string date)
15         {
16             string tmp = "";
17             foreach (char item in date)
18             {
19                 switch (item)
20                 { 
21                     case '0':
22                         tmp += "零";
23                         break;
24                     case '1':
25                         tmp += "一";
26                         break;
27                     case '2':
28                         tmp += "二";
29                         break;
30                     case '3':
31                         tmp += "三";
32                         break;
33                     case '4':
34                         tmp += "四";
35                         break;
36                     case '5':
37                         tmp += "五";
38                         break;
39                     case '6':
40                         tmp += "六";
41                         break;
42                     case '7':
43                         tmp += "七";
44                         break;
45                     case '8':
46                         tmp += "八";
47                         break;
48                     case '9':
49                         tmp += "九";
50                         break;
51                     default:
52                         tmp += item;
53                         break;
54                 }
55             }
56             return tmp;
57         }
58     }

2.   字段与属性:

      字段是女人;属性就是男人;

  女人就是在家里面做饭,洗衣服...,家就相当于一个类,一般情况下是不能让外面的人访问你的女人;所以要设成私有的(private);

  男人也是家一面的一员,家里面的事女人做了,男人就负责做外面的一些事情,打工,赚钱来保护女人,和外部打交道;

 3.   构造函数,初始化字段;(this 当前对象)
 
View Code
 1     class Student
 2     {
 3         //类默认有一个空的构造函数(默认构造函数)
 4         //当类中写了一个带参数的构造函数,则默认构造函数就没了
 5         public Student()
 6         { 
 7         }
 8 
 9         //构造函数  是一个特殊的方法
10         //快速初始化类内部的字段
11         public Student(string sNo,string name,int age)
12         {
13             //this是当前类的对象/实例
14             this.sNo = sNo;
15             this.name = name;
16             this.age = age;
17         }
18 
19         public Student(string sNo, string name, int age, string sex)
20             :this(sNo,name,age)
21         {
22             this.sex = sex;
23         }
24 
25        下面是一些字段,属性还有方法(只写了一个);
26         private string name;//按Ctrl+R+E它的属性就会自动出来
27         public string Name
28         {
29             get { return name; }
30             set { name = value; }
31         }
32      }  

4. 面向对象三大特征:封装、继承、多态

     (访问修饰符:public 任何地方;private 当前类中可以访问;protected 当前类及子类中可以访问;*internal 当前程序集可以访问)
 
继承:(base的用法,跟前面的this作用是一样的)
  不包含采用“0”参数的构造函数。(构造函数问题)
  未将对象引用设置到对象的实例。(编译的时候不会出错,运行的时候出错;这个错是没有给它分配内存,就去调用它的属性跟方法时出现的,看看有没有null)
  可访问性不一致(访问修饰符的问题)
父类
 1      //父类
 2     //基类
 3     class Person
 4     {
 5         public Person()
 6         { 
 7         }
 8         public Person(string name, int age, string sex)
 9         {
10             this.name = name;
11             this.age = age;
12             this.sex = sex;
13         }
14 
15         protected string name;
16         public string Name
17         {
18             get { return name; }
19             set { name = value; }
20         }
21 
22         private int age;
23 
24         public int Age
25         {
26             get { return age; }
27             set { age = value; }
28         }
29 
30         private string sex;
31 
32         public string Sex
33         {
34             get { return sex; }
35             set { sex = value; }
36         }
37 
38         public void SayHi()
39         {
40             Console.WriteLine("大家好,我是"+this.name);
41         }
42     }
子类

多态:不同的对象在执行同一的方法时,会产生不同的行为

里氏替换原则:  1父类引用指向子类对象   2父类对象不能够替换子类 (is-a 关键字as is)
 
View Code
抽象类与接口的区别及应用


抽象类(Abstract Class)与接口(Interface)是面向对象程序设计中两个重要的概念。由于两者在自身特性及应用方法上存在诸多相似性,如都不能实例化、都可以被继承(严格来说对于接口应该叫做实现),这么一来,在许多人心中抽象类与接口的界限非常模糊,对何时该使用抽象类、何时该使用接口更是感到困惑。

本文的目的是通过对两者的讨论与比较,帮助读者认清抽象类与接口在思想本质及应用场合方面的区别,如能做到这一点,读者便可以得心应手地根据具体情况正确选择和使用抽象类与接口。

1. 抽象类与接口是面向对象思想层面概念,不是程序设计语言层面概念

如若想正确认识抽象类与接口,首先要弄清楚的一点是,这两个概念均属于面向对象思想层面,而不属于某种程序设计语言。例如,C#中用interface关键字声明的语言元素,我们叫它“接口”,其实这是不准确的,准确来说,这应该叫做“接口在C#语言中的实现机制”。

面向对象思想包含许多概念,而不同面向对象语言对这些概念的具体实现机制各有不同。例如,C++中并没有一种关键字对应于C#中的interface,那么C++中就没有接口的概念了吗?非也!在C++中,如果想定义一个接口,可以通过将一个类中所有方法定义为纯虚方法[①]来做到。

这里可以看到,同样是接口,C#中用interface关键字来定义,而C++通过创建一个只包含纯虚方法的类来定义,这就是同一种概念在不同具体语言中具有不同的实现机制。类似的,C++中也没有abstract关键字用于定义抽象类,而是如果一个类中至少含有一个纯虚方法且它的方法不全为纯虚方法,则这个类被称为抽象类。

通过上面的分析可以看出,如果仅仅停留在语言层面去认知抽象类与接口,是无法准确理解两者的真谛的,因为不同语言对同一概念的实现机制有很大差别。如果一个C#初学者简单将两者理解为“用abstract修饰的类是抽象类,用interface定义的语言元素是接口”,那么当他接触C++时一定会感到困惑,因为C++里既没有abstract也没有interface,而是通过类中纯虚方法的情况确定这是个类、是个抽象类还是个接口。

明确了上面的问题,我们就可以给出抽象类与接口的真正定义了。

抽象类是不能实例化的类,但是其中的方法可以包含具体实现代码。

接口是一组方法声明的集合,其中应仅包含方法的声明,不能有任何实现代码。

以上对抽象类和接口的定义与任何具体语言无关,而是从面向对象思想角度进行的定义,不同语言可以有不同的实现机制。

从上面的定义中,我们可以发现两者在思想层面上的一项重大区别:抽象类是类(Class),接口是集合(Set),两者从本质上不是一种东西。这是我们总结出的第一个区别。请读者受累将上面加粗的字能放声朗十遍,声音越大越好,但是如果被室友或邻居扔鸡蛋请不要找我。

2. 抽象类是本体的抽象,接口是行为的抽象

在开始这一节之前,我想先请问各位一个问题,“我是一个人”和“我能呼吸”分别表达了“我”和“人”以及“我”和“呼吸”的关系,那么这两句话表达的是一种关系吗?如果你能很容易区分前者表示“是一个”的关系,而后者表示“能”的关系,那么恭喜你,你一定也能很容易区分抽象类和接口。

在阅读这一节时,请读者务必谨记上面这个问题以及下面这句话:

抽象类表示“是一个(IS-A)”关系的抽象,接口表示“能(CAN-DO)”关系的抽象。

请照例将上面的大声话朗读十遍。

好的,请各位擦干净头上的鸡蛋,我们继续。

从上面粗体字中我们可以看出,抽象类和接口有一个共性——它们都是“某种关系的抽象”,只不过类型不同罢了。其实如果将上面那句话的前半句中的“抽象类”改为“类”也是正确的,这并不奇怪,上文我们说过,抽象类只不过是一种特殊的类罢了。

下面我们先来解释IS-A关系。其实英语中的IS-A关系在汉语中可以解释为两种情况,当IS-A用在一个对象和一个类之间时,意思是“这个对象是类的一个实例”,例如关羽是一个对象,我们可以说“GuanYu IS-A General”,其中General(将军)是个类,这表示关羽是将军类的一个实例。而当IS-A用在两个类之间时,我认为叫做IS-A-KIND-OF更为准确,表示汉语中的“是一种”,如“General IS-A Person”,表示将军这个类是人这个类的一种,换用面向对象术语可以如下表述:General是Person的子类(Sub Type),Person是General的父类或超类(Super Type),General继承自Person。

这后一种IS-A关系,就是抽象类所表达的关系。分析到这里可以看出,抽象类所表达的关系其实就是面向对象三大特性之一——继承(Inheritance),也就是说,抽象类所表达的关系,与一般类与类之间的继承并无区别,而抽象类相比普通类,除了不能实例化外,也并无区别。之所以出现抽象类,是因为在较高抽象层次上,某些方法(往往是纯虚方法)无法实现,必须由其子类按照各自不同的情况具体实现。因为它含有纯虚方法,所以将这种类实例化在道理上讲不通,但我们又希望将这些子类中共有的部分抽象出来减少代码重复,于是就有了抽象类——它包含可复用部分,但又不允许实例化。

因此,抽象类的使用动机是在不允许实例化的限制下复用代码。请牢记这个动机。

接着再说说接口和CAN-DO关系。

我们知道,面向对象编程的基本思想就是通过对象间的相互协作,完成程序的功能。具体来说,在面向对象编程中,要求每个类都隐藏内部细节(这叫封装性),仅对外暴露一组公共方法,对象间就通过互相调用彼此的公共方法完成程序功能。

可以看到,面向对象思想中,对象和对象间根本不需要了解,调用者甚至可以完全不知道被调用者是谁,只要知道被调用者“能干什么”就行了。这就如同拨打110报警一样,你根本不知道对方长什么样、穿什么衣服、结没结婚、有没有孩子,你也不知道对方在哪,对象是谁,但是你知道对方一定“能接警”,所以你可以顺利完成报警。

这种“能干什么”就是CAN-DO关系,当我们把这种CAN-DO关系抽象出来,形成一个CAN-DO关系的集合,这就是接口了。那么使用接口的动机又是什么呢?动机之一是松散耦合。我们知道“低耦合”是面向对象程序设计中一个重要原则,而很大一部分耦合就是调用关系,面向对象中术语叫“依赖”。如果没有接口,调用者就要紧依赖于被调用者,就如同在没有110报警的年代,你只认识一个接警员,不知道其他接警员的电话,那么当你报警时,你必须给这个接警员打电话才行,如果哪天这个接警员休假或病了,你就无法报警了,除非你再去认识一个接警员。这时,我们说你紧依赖于这个接警员,也叫紧耦合。但有了110报警后就不一样了,我们将“可接警”看作一个接口,接口中有一个方法“接警”,而拨通110后,电话那头的人一定是实现了这个接口的,这时报警人不再依赖于具体接警员,而是依赖于“可接警”接口,这就叫做松依赖。

所以说,接口又可以看作一组规则的集合,它是对调用者的保证,对被调用者的约束。如上例中,可接警对报警人(调用者)保证调用对象可接警,同时约束接警部门必须把一个实现了这个接口的人安排在接警电话前面。哪怕这是个机器人或刚进行了两个小时接警培训的保洁员都没关系。

使用接口的另一个动机就是实现多态性[②]。

下面想象你被分配到一个全新的研发小组做主管,第一天上班的早晨,一群人站在你面前等着你训话,你完全不认识他们,也不知道他们各自的职务,但是你可以说一句“都去工作吧”,于是大家作鸟兽散,程序员去写程序,会计去核对账目,业务员出门联系客户……当你这样做的时候,你就利用接口实现了多态性。因为你知道,他们都实现了“可工作”这个接口,虽然各个人员对“工作”具体的实现不一样,但这不要紧,你只要调用他们的“工作”方法,他们就各自做自己的事情了。如果你不能面向接口去利用多态性,你就要一个个说:“程序员去写程序,会计去核账,业务员快出门联系客户……”,这实在非常的费劲。

对这一节的内容做一个总结:

抽象类表示“是一个(IS-A)”关系的抽象,它抽象了类的本体,其使用动机是在不允许实例化的限制下复用代码。接口表示“能(CAN-DO)”关系的抽象,它抽象了类的行为,其使用动机是松散对象间的耦合以及实现程序多态性。

好的,照例念十遍吧,不过这次我允许你默念,因为我怕这次飞来的不是鸡蛋而是砖头。

经过上面的分析,我想你已经可以很容易在抽象类与接口间做出选择了。如果你是为了将一系列类的公共代码抽出,减少代码的重复,并且这些类与抽象出来的类可以表述为IS-A关系,就用抽象类;如果你是为了将一个或一组行为抽象出来,用以松散对象间耦合或实现多态性,那就用接口吧。

3. C#中抽象类与接口的探讨

这一节我们讨论C#语言中一个是人尽皆知的区别:在C#中,一个类最多只能继承一个抽象类,但可以实现多个接口。

如果能充分理解抽象类对应于IS-A而接口对应于CAN-DO,则对这个约束不会感到奇怪。因为从逻辑上来说,一个类在所有相同抽象层次的类中只能“是其中一个”,但“能干多种事情”。这里的相同抽象层次指互相不存在继承关系的一个全集。

例如,{猪,牛,狗,猫} 可以看作具有相同抽象层次,其某个下层类只能是其中一个的子类,一个类不可能既是牛的子类又是猪的子类,但有可能既是牛的子类又是动物的子类,例如奶牛,这是因为“动物”与“牛”不在一个抽象层次上,“牛”本身就是“动物”的一个子类。

一般的,如果ClassA是ClassB的子类,同时也是ClassC的子类,那么一定存在ClassB是ClassC的子类或ClassC是ClassB的子类。

换句话说,一个类同时继承两个互相没有继承关系的类在逻辑上是不成立的。这就说明了为什么C#中不允许同时继承一个以上的抽象类。如果一个类要继承两个抽象类,那么从逻辑上来说,两个抽象类之间必然也存在继承关系,因此只需让该类继承较具体的那个抽象类即可。例如,本来的设计为“奶牛”同时继承“牛”和“动物”,但很容易发现,“牛”和“动物”已经存在继承关系,“牛”是继承于“动物”的,因此可将继承关系修改为“奶牛”只继承“牛”,而让“牛”继承于“动物”,这样就消除了多重继承。

而接口的CAN-DO关系在逻辑上不存在这样的矛盾,所以C#允许实现多个接口,具体为什么请读者自己思考。

顺便说一句,C++中允许多重继承是因为C++中非抽象类、抽象类和接口都用类来实现,而没有在语言层面区分成不同的语言元素,其实如果设计良好,也是不应该出现对抽象类的多重继承的,C#在语言层面上进行了约束,更有利于良好的设计,而C++对这方面比较灵活,需要开发者自己把握,因此C++对于初学者把握抽象类与方法更困难一些。

抽象方法:

    1.抽象的方法不写怎么实现的,让子类的方法去实现,也就是抽象方法不能有{};

    2.抽象方法必须出现在抽象类中;

    3.抽象方法必须在子类重写overrider;

抽象类:

    1.抽象类不能被实例化,可以用它的子类去实例化;

    2.一个类只能继承一个抽象类;

    3.抽象的成员不能使私有的;

用多态来实现 :计算形状Shape(圆Circle,矩形Square ,正方形Rectangle)的面积、周长
Shape
1     abstract class Shape
2     {
3         public abstract float GetArae();
4         public abstract float GetLong();
5     }
Circle
 1  class Circle : Shape
 2     {
 3         public Circle()
 4         { }
 5 
 6         public Circle(int r)
 7         {
 8             this.r = r;
 9         }
10 
11         private float PI = 3.14F;
12         private int r;
13         public int R
14         {
15             get { return r; }
16             set { r = value; }
17         }
18 
19         //ctrl + e + d 对齐代码
20         public override float GetArae()
21         {
22             return PI * r * r;
23         }
24 
25         public override float GetLong()
26         {
27             return 2 * PI * r;
28         }
29     }
Square
 1 class Square:Shape
 2     {
 3         public Square()
 4         { }
 5         public Square(int width, int height)
 6         {
 7             this.width = width;
 8             this.height = height;
 9         }
10         private int width;
11         public int Width
12         {
13             get { return width; }
14             set { width = value; }
15         }
16         private int height;
17         public int Height
18         {
19             get { return height; }
20             set { height = value; }
21         }
22         public override float GetArae()
23         {
24             return width * height;
25         }
26 
27         public override float GetLong()
28         {
29             return 2 * (width + height);
30         }
31     }
Program
 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             Shape[] shapes = { 
 6                              new Circle(5),
 7                              new Circle(6),
 8                              new Circle(7),
 9                              new Square(10,20),
10                              new Square(20,40)
11                              };
12 
13             foreach (Shape shape in shapes)
14             {
15                 if (shape is Circle)
16                 {
17                     Circle c = shape as Circle;
18                     Console.WriteLine("园==" + "半径:"+c.R);
19                 }
20                 else if (shape is Square)
21                 {
22                     Square s = shape as Square;
23                     Console.WriteLine("矩形=="+"长:"+s.Width + "---高:"+s.Height);
24                 }
25                 Console.WriteLine("面积:" + shape.GetArae());
26                 Console.WriteLine("周长:" + shape.GetLong());
27             }
28 
29             Console.Read();
30         }
31     }

抽象类跟抽象方法理解了,再来看虚方法 (virtual):

    1.虚方法给父类提供了一种默认的实现

    2.虚方法不能出现在密封类(sealed)中

 其实虚方法跟抽象方法是一样的,只是虚方法给父类一个默认的值;也就是虚方法必须要有{};
 

虚方法和抽象方法的区别:

    1.虚方法必须有实现{},抽象方法不能有实现
    2.抽象方法只能出现在抽象类中,虚方法随便
    3.抽象方法必须被子类重写(除非子类也是抽象类),虚方法可以被重写也可以不重写

这个有个面试里经常考的关于new的几点作用(/显示实现接口),把下面的执行结果自己能想出来就会懂了:

方法的隐藏
 1 namespace 方法的隐藏
 2 {
 3     class A
 4     {
 5         public void F()
 6         {
 7             Console.WriteLine("A.F");
 8         }
 9         public virtual void G()
10         {
11             Console.WriteLine("A.G");
12         }
13 
14     }
15     class B : A
16     {
17         public void A()
18         {
19             Console.WriteLine("B.A");
20         }
21         public void F()
22         {
23             Console.WriteLine("B.F");
24         }
25         public override void G()
26         {
27             Console.WriteLine("B.G");
28         }
29     }
30     class Program 
31     {
32         static void Main(string[] args)
33         {
34 
35             A a = new B();
36             a.F();
37             a.G();
38             Console.Read();
39         }
40     }
41 }

运用上面所学的知识来实现一个计算器(+、-、*、/)的功能

计算器程序思路
通过面向对象的思想创建计算器程序
    1、先分析计算机程序中的对象,我们把计算器看成对象
        计算器有两个数和计算的方法构成
        因为 + - * /分别需要两个数,并且要有一个计算的方法
        为了保证它们都有这两个数和方法
        所以创建一个父类,这个父类代表所有的计算
    2、创建抽象父类Operation,代表了所有的运算  抽象出来的父类
        属性 
            NumA:double
            NumB:double
        抽象方法 没有任何实现,要实现什么运算,必须通过子类重写  
             GetResult():double
    3、分别创建 + - * / 的具体类
        加法类  抽象父类Operation
            OperationAdd:Operation
                重写GetResult方法 实现加法

        其它的运算类似加法类
    4、创建OperationFactory类
        创建具体运算类的对象
        方法 
            Create(string oper):Operation
        根据is-a的原则,可以把子类对象赋给父类引用
        根据参数中的oper判断某种运算,返回某个具体对象
            例: case "+":
                o = new OperationAdd();
            具体代码参照项目
    5、在窗体中实现功能
Operation
 1     abstract class Operation
 2     {
 3         public Operation()
 4         {
 5         }
 6 
 7         public Operation(int numA, int numB)
 8         {
 9             this.numA = numA;
10             this.numB = numB;
11         }
12         private int numA;
13         public int NumA
14         {
15             get { return numA; }
16             set { numA = value; }
17         }
18 
19         private int numB;
20 
21         public int NumB
22         {
23             get { return numB; }
24             set { numB = value; }
25         }
26 
27         public abstract int GetRsult();
28     }
Factory
 1 class Factory
 2     {
 3         /// <summary>
 4         /// 生产加 减 的对象
 5         /// </summary>
 6         public static Operation CreateInstance(string type,int numA,int numB)
 7         {
 8             Operation oper = null;
 9             switch (type)
10             {
11                 case "+":
12                     //里氏替换原则
13                     oper = new Add(numA,numB);
14                     break;
15                 case "-":
16                     oper = new Sub(numA,numB);
17                     break;
18                 case "*":
19                     oper = new Mul(numA, numB);
20                     break;
21                 case "/":
22                     oper = new Div(numA, numB);
23                     break;
24                 default:
25                     throw new Exception("运算符错误");
26                     break;
27             }
28             return oper;
29         }
30     }
Add
 1 class Add:Operation
 2     {
 3         public Add()
 4         { 
 5         }
 6         public Add(int numA, int numB)
 7             :base(numA ,numB)
 8         { 
 9         }
10 
11         public override int GetRsult()
12         {
13             return base.NumA + base.NumB;
14         }
15     }
Sub
 1 class Sub:Operation
 2     {
 3         public Sub()
 4         { 
 5         }
 6 
 7         public Sub(int numA, int numB)
 8             :base(numA,numB)
 9         { 
10         }
11 
12         public override int GetRsult()
13         {
14             return base.NumA - base.NumB;
15         }
16     }
Mul
 1  class Mul:Operation
 2     {
 3         public Mul()
 4         { }
 5 
 6         public Mul(int numA, int numB)
 7             :base(numA,numB)
 8         {
 9         }
10         public override int GetRsult()
11         {
12             return base.NumA * base.NumB;
13         }
14     }
Div
 1 class Div:Operation
 2     {
 3          public Div()
 4         { }
 5 
 6          public Div(int numA, int numB)
 7             :base(numA,numB)
 8         {
 9         }
10         public override int GetRsult()
11         {
12             if (base.NumB == 0)
13             {
14                 throw new Exception("除数不能为0");
15             }
16             return base.NumA / base.NumB;
17         }
18     }
让按钮click事件指向btnOperation_Click
 1         private void btnOperation_Click(object sender, EventArgs e)
 2         {
 3             Button btn = sender as Button;
 4             if (btn != null)
 5             {
 6                 GetResult(btn.Text);
 7             }
 8         }
 9 
10         private void GetResult(string type)
11         {
12             Operation oper = Factory.CreateInstance(type, int.Parse(txtNumA.Text), int.Parse(txtNumB.Text));
13             lblResult.Text = oper.GetRsult().ToString();
14         }

计算器还可以参考《大话设计模式》里的第一部分,讲的简单工厂模式就是用的计算器例子

接口的例子:

ICollectHomework
1     interface ICollectHomework
2     {
3         void Collect();
4     }
Person
 1 public class Person
 2     {
 3         public Person()
 4         { 
 5         }
 6         public Person(string name, int age, Sex sex)
 7         {
 8             this.name = name;
 9             this.age = age;
10             this.sex = sex;
11         }
12 
13         protected string name;
14         public string Name
15         {
16             get { return name; }
17             set { name = value; }
18         }
19 
20         private int age;
21         public int Age
22         {
23             get { return age; }
24             set { age = value; }
25         }
26 
27         private Sex sex;
28         internal Sex Sex
29         {
30             get { return sex; }
31             set { sex = value; }
32         }
33        
34     }
Student
 1  public class Student:Person,ICollectHomework
 2     {
 3 
 4         //子类中的构造函数,默认调用父类的默认构造函数
 5         public Student()
 6         { 
 7         }
 8         public Student(string name, int age, Sex sex)
 9             :base(name,age,sex)
10         {
11             //base父类的对象
12         }
13 
14         public Student(string name, int age, Sex sex, int score) 
15             :base(name,age,sex)
16         {
17             this.score = score;
18         }
19 
20         private int score;
21         public int Score
22         {
23             get { return score; }
24             set { score = value; }
25         }
26 
27 
28         #region ICollectHomework 成员
29 
30         public void Collect()
31         {
32             Console.WriteLine("报告老师我交作业了");
33         }
34 
35         #endregion
36     }
Sex
1     enum Sex
2     {
3         男,女
4     }
Program
 1  class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             //传递的是实现了接口的对象
 6             Collect(new Student());
 7 
 8             //返回的是实现了接口的对象
 9             ICollectHomework icol = Create("student");
10             icol.Collect();
11             Console.Read();
12         }
13         //接口作为参数
14         static void Collect(ICollectHomework homework)
15         {
16             homework.Collect();
17         }
18         //接口作为返回值
19         static ICollectHomework Create(string type)
20         {
21             ICollectHomework icol = null;
22             switch (type)
23             {
24                 case "student":
25                     icol = new Student();
26                     break;
27                 case "teacher":
28                     icol = new Teacher();
29                     break;
30                 default:
31                     break;
32             }
33             return icol;
34         }
35     }
面向对象总结
面向对象 方便以后的扩展和维护

封装    黑匣子 隐藏具体实现
继承
    使代码可以重用
    子类继承父类的属性和方法 :
    单根继承性 继承具有传递性

    所有的类都直接或间接的继承自Object
    
    this 代表当前类的实例,base 代表父类的实例
    子类构造函数必须指明调用父类哪个构造函数
    访问级别约束
        子类的访问级别要比父类的低
        方法、属性等暴露的返回值、参数的数据类型不能比方法、属性或者所在类的可访问级别低
    
        
多态    不同对象执行同一行为(方法)有不同的表现
    
    里氏替换原则
        让父类引用指向子类对象
        Person per = new Student();
        per是父类的引用,它不知道有哪些子类
        不能使用父类的引用,调用子类的成员

    is    if (shapes[i] is Circle)
    as    Circle cir = shapes[i] as Circle;  如果转换失败返回null
    
    熟练计算形状的案例

抽象类和抽象方法 abstract
    抽象类
        不能被实例化的类  不能去new
        !!抽象类用来实现继承 和 多态
        抽象类定义的是公共的实现和能力(抽象方法,没有实现)
        抽象类中可以包含抽象成员,也可以不包含
        抽象类不能被密封
    抽象方法
        抽象方法不能有实现
        抽象方法必须出现在抽象类中
        抽象方法必须被子类重写(override),除非子类也是抽象类

多态的作用:把不同的子类对象都当作父类来看,可以屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,以适应需求的不断变化。


虚方法     ,虚方法给父类提供了一种默认的实现,
        子类可以使用override重写虚方法
        虚方法不能出现在密封类(sealed)中

虚方法和抽象方法的区别
    虚方法可以有实现,抽象方法不能有实现
    抽象方法只能出现在抽象类中
    抽象方法必须被子类重写,虚方法可以被重写也可以不重写


(*)密封类  sealed  不能被继承的类,调用密封类成员更高效



接口
    接口是定义类的一组标准和规范
    接口的出现是为了解决类的单根继承性


    接口不能被实例化
    可以同时实现多个接口,如果同时继承类和实现接口,类必须在最前
    接口可以继承接口
    接口中的成员不可以加访问修饰符,隐式为public
    接口中的成员不能有实现
    接口中的所有成员必须在子类中去直接实现
    接口中可以包含属性、方法,但不能包含字段,构造函数
    


接口和抽象类
    抽象类中可以有实现而接口中没有实现
    抽象类和接口都不能被实例化
    接口的成员在子类中直接实现,抽象类中的抽象成员要重写override

 5.  类型转换CAST:

  类型转换Cast是在内存级别上的转换。内存中的数据没有变化,只是观看的视角不同而已。
 
  隐式转换:当目标类型一定能满足源类型转换过去后的要求的话就是隐式转换;
  显式转换:如果当目标类型不一定能满足源类型转换过去后的要求的话就需要显式转换(程序员自己负责)。
 
  
  Convert.ToInt32()在null时不抛异常而是返回0;
  Int32.Parse()要抛异常;
  Int32.TryParse()不抛异常,会返回true或false来说明解析是否成功,如果解析错误,调用方将会得到0值。
 
  效率Int32.TryParse()优于Int32.Parse()优于Convert.ToInt32()。
  因 为:Convert.ToInt32会把最终的解析工作代理给Int32.Parse,而Int32.Parse和Int32.TryParse则分别把 解析工作直接代理给Number.ParseInt32和   Number.TryParseInt32,前者在出现解析错误时会抛出异常,而后者则仅仅返回 false。
 
 6.  String 字符串,不可变特性。字符串可以看成字符数
      
  属  性
    •Length
  方  法
     •IsNullOrEmpty() 静态方法
•ToCharArray()
•ToLower() 字符串的不可变
•ToUpper()
•Equals() 忽略大小写的比较
•Join() 静态方法
•Format () 静态方法
•IndexOf()
•LastIndexOf()
•Substring()
•Split() Replace() Trim()
 
7.  StringBuilder
 
    StringBuilder sb = new StringBuilder();
    sb.Append();
    sb.ToString();
    sb.Insert();
    sb.Replace();
 
 
 
 
 
 
 
  
 
  
 
 
 
 
原文地址:https://www.cnblogs.com/hejinyang/p/2808854.html