【004】◀▶ C#学习(三) - 面向对象编程
《C#入门经典(中文第四版)》第8章 - 第10章学习笔记
---------------------------------------------------------------------------------------------------------
●·● 目录:
A1 ………… 类(Class)
A2 ………… 类的特点
A3 ………… 类的访问级别
A4 ………… 类的定义
A5 ………… 接口(Interface)
A6 ………… 数据成员
A7 ………… 方法(Method)
A8 ………… 属性(Property)
A9 ………… 字段(Field)
Aa ………… 构造函数和析构函数
Ab ………… 索引器
Ac ………… 抽象类和抽象函数
Ad ………… 密封类和密封函数
Ae ………… 其他
Af ………… 一些技巧
---------------------------------------------------------------------------------------------------------
╔════════╗
╠════╣ 第A1个 ╠══════════════════════════════════════════════════╣
╚════════╝
●·● 类(Class):
1. 类是指一个抽象的模板、模型,而对象则是一个实例,是具体的。《C#3.0从基础到项目实践》—P147
- 那 么什么是对象呢?从一般意义上讲,对象是现实世界中一个实际存在的事物,它可以是有形的(例如一个人、一本书),也可以是无形的(例如一个计划、一次会 议)。对象是构成世界的一个独立单位,它具有自己的静态特征(可以用某种数据来描述)和动态特征(对象所表现出的行为或具有的功能)。例如,对于一个学生 对象,有学号、性别、班级、家庭住址等静态特征,也有选课、听课、考试等动态特征。
- 面向对象编程的对象,即系统中用于描述客观事物的一个实体,是构成系统的一个基本单位。对象由一组数据成员和一组函数成员构成。数据成员是用于描述对象静态特征的数据项。函数成员是用于描述对象动态特征的操作序列。
- 和 对象紧密关联的一个概念是类,那么什么是类呢?我们知道,把众多的事物归纳,再划分为一些类,就是人类在认识客观世界时经常采用的思维方法。分类所依据的 原则是抽象,即忽略事物的非本质特征,只注意那些与当前目标相关的本质特征,从而找出事物的共性,把具有相同性质的事物划分为一类,得出一个抽象的概念。 注意,类知识一个抽象的概念,客观世界中并不存在这样的一个实际物体。例如,不存在一个实际物体叫学生,存在的是学生张三、李四、王五等一个个对象。
- 面向对象编程中的类,是具有相同数据成员和函数成员的一组对象的集合,它为属于该类的全部对象提供了抽象的描述。类与对象的关系犹如模具与铸件之间的关系,一个属于某类的对象称为该类的一个实例。
---------------------------------------------------------------------------------------------------------
╔════════╗
╠════╣ 第A2个 ╠══════════════════════════════════════════════════╣
╚════════╝
●·● 类的特点:
1. 面向对象编程的基本特点:封装、继承和多态
- 封装:
- 就是把某个事物包起来,使外界不知道该事物的具体内容。面向对象技术中的封装,简单来说就是将代码及其处理的数据绑定在一起,形成一个独立单位,对外实现完整功能,并尽可能隐藏对象的内部细节。
- 通过这种机制,能够保证程序和数据都不受外部干扰且不被勿用。以手机为例,每个用户都懂得如何使用手机接打电话和收发信息,而不必了解其内部的集成电路和工作原理。
- 继承:
- 也称派生,指的是特殊类的对象自动拥有一般类的全部数据成员与函数成员(构造函数和析构函数除外)。
- 被继承的类称为父类,也称为基类或一般类。继承的类称为子类,也称为派生类或特殊类。继承具有传递性,如果类C继承类B,类B继承类A,则类C继承类A。因此,一个类实际继承了它所在的类等级中在它上层的全部基类的所有描述。
- 类继承允许且只允许单一继承,即一个派生类只能继承一个基类,但是可以继承于多个接口,用comma隔开。
- 子类可以访问父类的共有成员public和保护性成员protected,不能访问父类的私有成员private,虽然私有类成员也被继承下来。
- 派生类可以继承基类的所有成员,除了基类的构造函数和析构函数。
- 在派生类中,如果存在和基类同名的方法就会隐藏基类中的方法,但是通过base.<MethodName>()可以调用基类的方法。
- 在实际编程中,如果派生类的方法和基类中的方法同名,通常在方法前加new关键字显示隐藏,或者用override关键字表示重写。
- 派生类的构造函数和析构函数
-
View Code - 派生类构造函数
- 如果派生类中没有显示调用基类的构造函数,则默认情况下系统会自动调用基类的无参数构造函数。如果要执行基类的有参构造函数,必须在派生类构造函数的成员初始化表中显示指出。(相当于先执行:base的构造函数,再执行派生类的构造函数)
-
View Code - 派生类构造函数
- 其中构造函数的执行次序一定要分析清楚。另外,加入基类A中没有提供无惨构造函数public A(){x=0;},则在派生类的任何构造函数成员初始化表中必须显示指出基类A的有参构造函数A(i)。
-
View Code - 综合练习
- 派生类的访问权限要低于基类的访问权限
- 继承基类和继承接口的时候,要先写基类,然后用comma隔开写接口名称。
- 多态:
- 指一般类中定义的属性或行为,被特殊类继承之后,可以具有不同的数据类型或表现出不同的行为。
- 这使得同一个属性或行为在一般类及其各个特殊类中具有不同的语义,表现为“多姿多彩”。
- http://www.cnblogs.com/jhxk/articles/1644018.html
- 当 派生类继承基类时,会获得基类的所有方法、字段、属性和事件。若要更改基类的数据和行为,可以使用新的派生成员替换基类成员,或重写虚拟的基成员。使用新 的派生成员替换基类的成员需要使用new关键字。如果基类定义了一个方法、字段或属性,则new关键字用于派生类中穿件该方法、字段或属性的新定义。而基 类成员不会被替换,而是被隐藏,成为隐藏成员。new关键字放置在要替换的类成员的返回类型之前。public void DoWork(){} public new void DoWork(){}
- 如果将派生类的实例强制转换为基类的实例,就仍然可以调用隐藏类成员。
- 为 了使派生类的实例完全接替来自基类的类成员,基类必须将该成员声明为虚拟的,通过在该成员的返回类型之前加virtual关键字实现。然后,派生类可以选 择使用override关键字而非new关键字,将基类实现替换为自身的实现。其中,可以虚拟的成员不能是字段,只能是方法、属性、事件和索引器。
- 在派生类中重写虚方法时,要求派生类中的所有都与基类相同,只有虚方法和抽象方法才能被重写。
- →可以将派生类对象赋值给基类,但是此时的基类对象只具备基类的属性和方法,但是反过来不可以。
View Code - @Me
---------------------------------------------------------------------------------------------------------
╔════════╗
╠════╣ 第A3个 ╠══════════════════════════════════════════════════╣
╚════════╝
●·● 类的访问级别:
1. 成员访问级别:(字段、方法、属性都可以叫做类的成员)
- Public:任何地方都可以访问
- Private:默认级别,只能在类中访问
- Protected:可以通过派生类访问基类中的Protected
---------------------------------------------------------------------------------------------------------
╔════════╗
╠════╣ 第A4个 ╠══════════════════════════════════════════════════╣
╚════════╝
●·● 类的访问级别:
1. 类的定义:
- internal:内部,默认情况下,类是工程内部的,修饰符为internal,即只有当前工程中的代码可以访问。
- public:公共,如果使用修饰符public,即为公共类,那么在工程间也可以使用。
- private:私有,访问仅限于类本身。
- protected:受保护,访问限于类本身,或从包含类派生的类型。
- abstract:抽象,该类不能生成实例。
- sealed:密封,该类不允许被继承。
- new,只嵌套用,表明类中隐藏了由基类中继承来的,与基类中同名的类型。
---------------------------------------------------------------------------------------------------------
╔════════╗
╠════╣ 第A5个 ╠══════════════════════════════════════════════════╣
╚════════╝
●·● 接口(Interface):
1. 接口:
- 接口的定义与类相似,用interface关键字。
- 默认关键字为internal,可以用public,但是不可以用abstract和sealed关键字。类可以继承多个接口。接口不是类,所以没有继承System.Object.
- 与类相同,接口也定义了一些方法、属性、索引和事件。但与类不同的是,接口并不提供实现,它只是一种约定,实现接口的类或结构必须遵守该接口定义的约定。一个接口可以从多个及接口继承,而一个类或结构可以实现多个接口。
- 当类或结构继承接口时,意味着该类或结构为该接口不顶,对不起小.弟.弟,所以顶顶顶...的所有成员提供实现。接口本身不提供类或结构能够以继承基类功能的方式继承的任何功能。但是,如果基类实现接口,派生类将继承该实现。
---------------------------------------------------------------------------------------------------------
╔════════╗
╠════╣ 第A6个 ╠══════════════════════════════════════════════════╣
╚════════╝
●·● 数据成员:
1. 数据成员:
- static修饰符声明的字段为实例字段,静态字段,无论存在多少类实例,它们都共享一个静态字段拷贝,直接用<类名>.<静态字段>就可以调用,不需要用实例来调用。public static int count;
- const常量必须在声明的同时对其进行赋值,指定值之后就不能修改;public const string country = "China";
- readonly只读字段则可以在声明时被初始化,或者通过构造函数初始化。需要注意的是,在声明时,被初始化后还可以通过构造函数再次赋值。public readonly double width = 30;
---------------------------------------------------------------------------------------------------------
╔════════╗
╠════╣ 第A7个 ╠══════════════════════════════════════════════════╣
╚════════╝
●·● 方法(Method):
1. 方法:
- 方法可以是实例的方法,也可以是静态的方法,默认情况下是实例的方法。静态方法需要使用static声明。静态方法不与实例关联,实例方法对类的某个给定的实例进行操作。通过<类名>.<静态方法名>()来调用。
- 在一个类的内部,静态方法只能调用静态成员,实例方法即可调用实例成员,也可调用静态成员。再类的外部要调用静态方法只需要类名加方法名;在类的外部要调用实例方法,需要首先生成一个实例,然后通过实例名加方法名进行调用。
- 在一个类中,允许有同名的方法存在,为区分这些重名的方法,要求他们有不同的参数、不同的参数个数或不同的参数类型,即所谓的方法重载。
-
View Code - 函数重载
- virtual——方法可以重写。
- abstract——方法必须在非抽象的派生类中重写(只用于抽象类中)。
- override——方法重写了一个基类方法(如果方法被重写,就必须使用该关键字)。
- extern——方法定义放在其他地方。
---------------------------------------------------------------------------------------------------------
╔════════╗
╠════╣ 第A8个 ╠══════════════════════════════════════════════════╣
╚════════╝
●·● 属性(Property):
1. 属性:
- 属性开头字母大写,字段开头字母小写。为属性赋值时使用set访问器,set访问器始终使用关键字value设置属性的值;获取属性值时使用get访问器,get访问器通过return返回属性值。
- 属性能够方便控制数据的读写性。在属性声明中若只有get访问器,则为只读属性;若只有set访问器,则为只写属性;若既有get访问器又有set访问器,则为读写属性。
- 属性可以对读、写的访问权限分别设置。可以为get、set设置不同的访问修饰符(公共、保护或私有),使其具备不同的访问级别。但需要注意,get、set访问器也可以不带访问修饰符,此时默认和属性的访问修饰符相同。
-
View Code - set & get
- public int Age{get; set;}没有特殊要求,可以自动生成
- Age不保存值,保存在age中,属性可以控制给值。
---------------------------------------------------------------------------------------------------------
╔════════╗
╠════╣ 第A9个 ╠══════════════════════════════════════════════════╣
╚════════╝
●·● 字段(Field):
1. 字段:
- 字段可以使用关键字readonly,表示这个字段只能在执行构造函数的过程中赋值,或由初始化赋值语句赋值。只能在字段声明或在构造函数中给它赋值。
---------------------------------------------------------------------------------------------------------
╔════════╗
╠════╣ 第Aa个 ╠══════════════════════════════════════════════════╣
╚════════╝
●·● 构造函数和析构函数:
1. 构造函数和析构函数:
- 构造函数的名称必须与类名相同。
- 构造函数可以带参数,但没有返回值。
- 构造函数在对象定义时被自动调用。
- 若没有为类定义构造函数,则系统会生成默认的构造函数。
- 构造函数可以被重载,但不可以被继承。public MyNumber() public MyNumber(int number)
- 在需要时,可以自定义构造函数,一旦用户编写了构造函数,编译器就不再提供默认的构造函数。只有在未定义任何构造函数时,编译器才会自动提供默认的构造函数。
-
View Code - 构造函数重载
- 这个构造函数初始化了相同的字段,显然应把所有代码放置在一个位置。C#中有一个特殊的语法,称为构造函数初始化器,可以实现此目的。
-
View Code - 构造函数初始化器
---------------------------------------------------------------------------------------------------------
╔════════╗
╠════╣ 第Ab个 ╠══════════════════════════════════════════════════╣
╚════════╝
●·● 索引器:
1. 索引器:
- 索引符(indexer)是一种特殊类型的属性,可以把它添加到一个类中,以提供类似数组的访问。实际上,可以通过索引符提供更复杂的访问,因为我们可以用方括号语法定义和使用复杂的参数类型。它最常见的一个用法是对项执行简单的数字索引。
-
View Code - 索引器举例
-
View Code - 索引器举例(CollectionBase)
---------------------------------------------------------------------------------------------------------
╔════════╗
╠════╣ 第Ac个 ╠══════════════════════════════════════════════════╣
╚════════╝
●·● 抽象类和抽象函数:
1. 抽象类和抽象函数:
- 抽象类表示一种抽象的概念,用于为其派生类提供一个公共接口。抽象类由abstract修饰符声明。抽象类只能作为其他类的基类,而不能直接实例化,对抽象类使用new关键字会发生错误。
- 抽象函数没有实现代码,而是由abstract修饰符声明。抽象函数只提供函数名称,具体实现交由继承的派生类。
- 抽象类可以包含抽象函数,也可以包含非抽象函数,而非抽象类不能包含抽象函数。包含抽象函数的类一定是抽象类。当从抽象类派生非抽象类时,非抽象类必须具有实现所继承的所有抽象函数,且必须使用override关键字重写抽象类所定义的函数。
-
View Code - 举例
---------------------------------------------------------------------------------------------------------
╔════════╗
╠════╣ 第Ad个 ╠══════════════════════════════════════════════════╣
╚════════╝
●·● 密封类和密封方法:
1. 密封类和密封方法:
- 抽象类和抽象函数主要用在为派生类提供公共接口的场合,抽象函数需要且必须被派生类实现,相反,也可以限制某些类和方法被继承和扩展,这是需要借助密封类和密封方法的语法机制实现。
- 当类和方法被sealed修饰时,就成为了密封类和密封方法。对类来说,这表示不能继承该类;对于方法来说,这表示不能重写该方法。
---------------------------------------------------------------------------------------------------------
╔════════╗
╠════╣ 第Ae个 ╠══════════════════════════════════════════════════╣
╚════════╝
●·● 其他:
1. 练习:聊天机器人!
2. OOP - Object-Oriented Programming - 面向对象编程
3. UML - Universal Modeling Language - 通用建模语言
4. try catch 接收异常:
-
1 try
2 {
3 int i = Convert.ToInt32("123");
4 Console.WriteLine(i);
5 }
6 catch (System.Exception ex)
7 {
8 Console.WriteLine("Data Error");
9 } - 在发生异常前面的代码执行,发生异常后面的代码不会被执行,出了try-catch还会正常执行程序!
- Exception类:http://msdn.microsoft.com/zh-cn/library/c18k6c59.aspx
- Exception类属性:
- Message:获取描述当前异常的消息。
- StackTrace:获取调用堆栈上直接帧的字符串表示形式。
-
View Code - 异常举例
-
View Code - 抛出异常
5. 在static成员中不能调用非static成员,在非static成员中可以调用static成员。static成员与具体实例无关。
6. 接口与抽象类
- 接口不能包含字段、构造函数、析构函数、静态成员或常量。
7. 结构与类
- 结构和类非常相似,但结构是值类型,而类是引用类型。
8. 一些概念:
- this关键字:引用对象实例,指当前的对象实例,因此不能在静态成员中使用this关键字,因为静态成员不是对象实例的一部分。
---------------------------------------------------------------------------------------------------------
╔════════╗
╠════╣ 第Af 个 ╠══════════════════════════════════════════════════╣
╚════════╝
●·● 一些技巧:
1. 将当前选择作为启动项目的方法:
2. 通过 右键》解析 可以找到引用~也可以直接通过点击图标实现,如下图:
3. Class Details窗口,可以显示类的内容,并且可以直接建立方法、属性、字段,如下图:(选中类,自动会显示)
4. 在类图(Class Diagram)中,通过拉动工具箱,可以建立类、枚举等等,如下图所示:
5. 建立成员与类型之间的关系,在成员上右击》显示为关联,取消方法为,在成员上右击》显示为字段,如下图:
6. 通过字段,右键》重构》封装字段,可以将字段转成属性,如下图: