第一章 C#概述
1.1 C#语言特点
C# 是一种面向对象的语言。
1.3 C#程序特点
1.必须定义类 。
2.类的代码主要由方法组成。
第二章 C#程序设计基础
2.1 常量与变量
2.1.1 常量
1.无符号整型常量书写时添加 u 或 U 标志。
2.长整型常量书写时添加 l 或 L 标志。
3.单精度浮点型常量书写时添加 f 或 F。
4.双精度型常量添加 d 或 D。
5.小数型常量 添加 m 或 M。
2.1.2 变量
1.变量名必须以 字母、下划线(_)、汉字 打头,可包含字母、数字、下划线(_) 和 汉字。
2.系统运行时,系统自动为变量分配内存单元。
3.float x = 1.2;
是错误的,应该写作 float x = 1.2f
。
2.2 C#的数据类型
从数据存储的角度,数据类型分为值类型(值)、引用类型(引用)。
2.2.1 简单类型
整数型:
浮点型:float 、double
小数型:decimal
布尔型:bool
2.2.2 枚举型enum
enum Months { Jan, Feb, Mar, Apr, May, Jun, Jul, Augt, Sep, Oct, Nov, Dec};
1.枚举元素的数据值是确定的,一旦声明就不能在程序运行中修改。
2.枚举元素的个数是确定的。
3.默认枚举元素的第一个值为
0
0
0,且后面依次加一。
4.定义时可以改变取值规则,重写枚举元素的值即可。
2.2.3 结构型struct
1.C#的结构型必须使用struct来标记。
2.成员包括数据成员、方法成员等。
2.2.4 数据类型转换
隐式转换
1.转换时,先转换成同一类型,然后进行运算。
2.转换时按数据长度增加的方向进行,保证精度不降低,比如int型和long型运算。
3.所有浮点型都是以双精度进行的。
4.byte和short参与运算时,必须转成int型。
5.char类型可以转换成其他很多类型,但很多其他类型不存在隐式转换到char。
显式转换
1.显式转换是明确要求编译器完成的转换,可能会造成精度损失。
两种转换都是为了本次运算的需要而作的临时转换,而不改变数据本身的类型。
C#类型转换方法
1.System.Convert类,提供类型转换方法来转换数据类型。如:ToBoolean、ToByte、ToChar、ToInt32。
2.简单类型自带Parse方法,把字符串解析转化为指定类型。如:double.Parse()。
3.数据类型均自带ToString方法,将数据类型转化为字符串。
2.3 运算符与表达式
2.3.1 算术运算符与表达式
1.与 C++ 相同。
2.3.2 赋值运算符与表达式
1.赋值号左右的数据类型如果不同,则系统将自动把赋值号右边的类型转换为左边的类型再赋值,并且不能将右边数据长度更大的数值隐式转换赋给赋值号左边的数据长度更小的数据类型。
2.3.3 关系运算符与表达式
1.关系运算符优先级低于算术运算符。
2.关系运算结果只能为true或false。
2.3.4 逻辑运算符与表达式
1.逻辑运算符优先级低于关系运算符,高于赋值运算符。
2.逻辑运算结果只能为true或false。
2.4 数组和字符串
数组的秩又称为数组的维度。
2.4.1 一维数组
1.声明和创建 数组类型 [] 数组名 = new 数组类型[数组长度]
。可以先声明后创建。
2.初始化数组有多种方式:①创建时初始化。②先声明后初始化。③先创建后初始化。
①string[] arrayA = { "Shirdrn", "Hamtty", "Saxery" };
②string[] arrayB; arrayB = new string[3]{ "shirdrn", "Hamtty", "Saxery" };
③string[] arrayC = new string[3]; arrayC[0] = "Shirdrn";
3.C#数组类型是从抽象基类System.Array派生的。
4.Array类的方法成员:Clear、Copy、Sort、Reverse、Indexof、LastIndexOf、Resize等,Sort、Reverse、IndexOf、LastIndexOf、Resize只能针对一维数组。
2.4.2 多维数组
1.声明和创建 数组类型 [逗号列表] 数组名 = new 数组类型[维度长度列表]
其中逗号+1就是维度。float[, ,] b = new float[2, 4, 3]{ };
2.初始化相关:①同一维度的初始值放在一对{}里。②可以省略长度列表,系统能自动计算。③初始化多维数组可以采用简写形式。如果先声明多维数组再初始化,就不能采用缩写形式。
2.4.3 数组型数组
1.声明和创建数组类型[维度][子数组的维度] 数组名 = new 数组类型[维度长度][子数组的维度]
。
int[][] a=new int[2][];a[0]=new int[1];a[1]=new int[4];
其中,省略维度为一维数组,省略子数组的维度表示子数组为一维数组。
2.初始化相关:与一维数组初始化相同。
2.4.4 字符串string
1.字符串常量用双引号来标记,字符串变量用string来声明。
2.C#字符串是不可变的,一旦创建,其内容就不能更改。
// 初始化的字符串的不可修改的,但是可以追加字符,且原字符串不会被销毁。
第三章 C#程序的流程控制
3.1 C#程序的分支语句
3.1.1 if语句
3.1.2 switch语句
1.不同case后面的常量值是否可以相同?不可以
2.一个case可以使用它下面case的语句块吗?可以
3.每个带语句块的case最后都要写break吗?是的
3.2 C#程序的循环语句
表达式的变量必须为布尔型表达式
3.2.1 while语句
3.2.2 do/while语句
1.至少执行一次。
3.2.3 for语句
3.2.4 foreach语句
循环访问数组或集合的元素,又成迭代器。
格式:foreach(类型 循环变量 in 表达式)
表达式一般是一个数组名或集合名
1.自动指向数组或集合的第一个元素。
2.若元素不存在则退出循环。
3.元素的值赋值给循环变量。
4.自动指向下一个元素。
3.2.5 循环语句的嵌套
3.3 跳转语句
3.3.1 break语句
3.3.2 continue语句
第四章 面向对象程序设计入门
4.1 面向对象的基本概念
4.1.1 对象
1.客观世界中任何一个事物都可以看成一个对象。
2.对象是构成系统的基本单位。
3.任何一个对象都具备两个要素,属性和行为(方法+操作)。
4.1.2 事件与方法
1.事件,向对象发出的服务请求。
2.方法,表示对象能完成的服务或执行的操作功能。
4.1.3 类与对象
1.类表示具有相同属性和行为的一组对象的集合,为该类的所有对象提供统一的抽象描述。
4.1.4 抽象、封装、继承与多态
1.抽象:不再赘述。。
2.封装和信息隐藏两个含义:一是把数据和操作封装在一个对象中,形成一个基本单位。各对象相互独立,互不影响。二是隐藏内部细节,留下接口对外联系和接受信息。有利于数据安全,防止修改。
3.继承:不再赘述。优点:降低软件开发的复杂性和费用,使软件系统易于扩充,大大缩短了软件开发周期,对于大型软件的开发具有重要的意义。
4.多态:基类被继承后的派生类的对象,存在的差异性。实现方式:在派生类中重新定义从基类继承过来的数据类型或方法(覆盖)
4.2 类的定义与使用
4.2.1 类的声明和实例化
1.类的声明:[访问修饰符] class 类名 [:基类] { 类的成员; }
2.对象的声明: 类名 对象名
对象的实例化:对象名 = new 类名();
Student stu1; stu1 = new Student();
也可以在声明的时候实例化:类名 对象名 = new 类名();
Student stu2 = new Student();
4.2.2 类的可访问性
1.访问修饰符包括:public、private、internal、protected、protected internal。
public:公共的,访问不受任何限制,允许跨程序集引用,可用来修饰类及其成员。
private:私有的,只允许在该类内部使用,不允许其他类访问,只能用来修饰类成员。
protected:受保护的,只允许该类及其派生类使用, 只能用来修饰类成员。
internal:内部的,只允许在当前程序集内部使用,可用来修饰类及其成员。
protected internal:仅限于当前程序集内部使用,只允许该类及其派生类使用, 只能用来修饰类成员。
2.未指定修饰符时,类的成员默认为private。
3.第一级类型可访问性只能是public和internal。未指定修饰符时,默认可访问性是internal
4.命名空间不可修饰,无访问限制。
4.2.3 值类型与引用类型
1.值类型:简单类型、结构类型、枚举类型。在定义时分配空间。。
2.引用类型:数组、字符串、类、接口、委托。实例化后才分配空间。
4.2.4 装箱与拆箱
1.C#允许将任何类型的数据转换为对象,或者将任何类型的对象转换为与之兼容的值类型。
2.装箱:把值类型转化为对象类型(隐式转换,对象类型是Object,最终基类)。
int i = 100; object x = i;
拆箱:把对象类型转化为值类型(显式转换)
long k = (long)x;
4.3 类的成员及其定义
类的成员包括:常量、字段、属性、索引器、方法、事件、构造函数、析构函数…
4.3.1 常量与字段
常量
常量的值固定不变,是一种符号常量,由用户创建并反复使用。
常量定义使用const关键字,定义时指明名称和值。
声明格式如下:[访问修饰符] const 数据类型 常量名 = 常量的值;
字段
字段表示类的成员变量。
声明格式如下:[访问修饰符] 数据类型 字段名;
使用readonly可设置为只读字段。
1.只读字段可以在声明或初始化时赋值。
2.在声明时为只读字段赋值与使用常量没有什么区别。
3.在对象初始化时,为只读变量赋值需要使用构造函数使用。
4.3.2 属性
字段描述了类的数据信息,如何控制对字段的使用方法?
1.定义属性的一般形式如下:[访问修饰符] 数据类型 属性名{ get { //获取属性的代码,用return 返回值 } set { //设置属性的代码,用value赋值 } }
2.如果访问器(get)由单行语句构成,可以将属性用表达式主体定义。
get => 私有字段;
set => 私有字段 = value
4.3.3 方法
1.方法的访问修饰符:public、protected、private、internal、 protected internal 默认访问修饰符:private
2.方法的调用:非静态类:同类调用:this.方法名(参数列表)。其他类调用:对象名.方法名(参数列表)。
4.3.4 构造函数
4.4 方法的参数传递
参数传递就是将实参传递给形参的过程。
方法的参数传递按性质可分为按值传递与按引用传递。
4.4.1 按值传递
1.值传递是一种单向值传递。
2.值类型的参数在传递时默认按值传参。string和object虽然是引用型数据,但从表现形式来看,仍具有按值传参的效果。
4.4.2 按引用传参
1.当值类型和string类型参数要按引用方式传参时,可以通过ref关键字来声明引用参数。
2.形参、实参,都必须添加ref关键字。
4.4.3 输出参数
1.一个方法可允许有多个输出参数。
2.形参、实参都使用out关键字来声明。
3.out修饰的实参可以不进行初始化。
4.4.4 引用类型参数
1.引用类型参数(string除外)总是按引用传递,不用ref或out关键字。
4.4.5 数组型参数
1.形参数组前不添加params修饰符,实参是一个数组名。
2.形参数组前添加params修饰符,对应的实参可以是数组名,也可以是数组元素值的列表。
3.params只能修饰任意类型的一维数组,不能与ref和out公用。每个方法只能有一个params数组且在形参列表最后。
4.5 方法的重载
1.重载一同二不同:名同,参数类型或参数个数不同。
4.6 对象的生命周期
值类型分配内存用栈,引用类型使用堆。
4.6.1 对象的生命周期
1.使用new创建对象,获得内存。
2.对象初始化,包括对象的数据成员的初始化。
3.适用对象,包括访问数据成员、调用方法成员。
4.释放对象所占用的资源,如关闭磁盘文件,网络连接等。
5.释放地向,回收内存(由垃圾回收期自动完成)。
4.6.2 终结期(析构函数)
1.一个类只能有一个析构函数。
2.无法继承或重载析构函数。
3.析构函数既没有修饰符,也没有参数。
第五章 面向对象的高级程序设计
5.1 静态成员与静态类
5.1.1 静态成员
静态成员(方法、字段、属性或时间) -> static
静态成员属于类,需要通过类来访问;
非静态成员通过实例(对象)来访问。
5.1.2 静态构造函数
用来 初始化类的静态字段。
不能直接调用静态构造函数。
静态构造函数在类的第一个实例创建之前或者调用类的任何静态方法之前执行,而且最多执行一次。
静态构造函数可以与实例构造函数共存。
静态构造函数不能带访问修饰符,不能有参数列表,不能有返回值,不支持重载。
5.1.3 静态类
静态类使用static关键字声明,
有以下特点:
1.仅包含静态成员。
2.不能被实例化。
3.是密封的,不能被继承。
4.不能包含实例构造函数。
有以下优点:
1.能够自动检查,确保不添加实例成员。
2.使程序实现更简单、迅速,因为不必创建对象就能调用其方法。
举例:Math、Console。
5.2 类的继承性
1.派生类只能从一个类中继承。
2.继承了 除了基类构造函数以外的基类成员。
3.类的继承可以传递。
5.2.1 派生类的声明
派生类可以拥有自己的成员,隐式从基类继承成员。
5.2.2 构造函数
派生类在创建对象时,先调用基类的构造函数再调用派生类构造函数。
5.2.3 密封类
阻止类被其他类继承 -> sealed
5.3 类的多态性
派生类允许扩展基类的成员,也可以重写基类的方法成员,以更改基类的数据和行为。
C#提供了两种选择,一是使用新的派生成员替换基类成员,二是重写虚拟的基类成员。
基类对象可以引用派生类对象,反之不可以。
5.3.1 使用new重新定义类的成员
1.替换基类的成员:(在派生类里)用new关键字。
举例:
public string Eat() // 基类方法
{
return "ABC";
}
public new string Eat() // 基类方法
{
return "CDE";
}
2.用virtual和override定义类的成员。
基类中的声明格式: public virtual 方法名称([参数列表]){}
派生类的声明格式: public override 方法名称([参数列表]){}
举例:
public virtual string Eat() // 基类方法
{
return "ABC";
}
public override string Eat() // 基类方法
{
return "CDE";
}
5.3.2 用virtual和override定义类的成员
使用virtual和override要注意:
1.字段不能是虚拟的,只有方法、属性、事件和索引器才可以是虚拟的。
2.使用virtual修饰符后,不允许再使用static、abstract、override修饰符。
3.派生类对象即使被强制转换为基类对象,所引用的仍然是派生类的成员。
4.派生类可以通过密封停止虚拟继承,此时派生类的成员使用sealed override声明
5.3.3 访问基类的成员
1.基类与派生类之间的转换
C#允许把派生类转化为基类,不允许把基类转换为派生类。
基类对象既可以指向基类实例,也可以指向派生类实例,用的还是派生类的数据成员。
5.4 抽象类
5.4.1 抽象类及其抽象成员
抽象方法不包含任何实现代码。唯一的作用就是让派生类重写。
只有抽象类,能定义抽象成员。
抽象类也可以定义非抽象成员,但抽象成员必须定义在抽象类中。
抽象关键字 abstract
5.4.2 重载抽象方法
1.派生类(非抽象类)定义中必须使用override重载基类的抽象方法或抽象属性。
2.派生类重写基类虚成员,也可以不重写基类的虚成员。
非抽象的派生类必须重载基类的抽象成员。
5.5 接口
接口包括方法、属性、事件、索引器。
接口不提供成员的实现,接口只指定实现该接口的类或结构必须提供的成员。
5.5.1 接口的声明
在C#中,声明接口使用 interface 关键字,一般形式如下:
[访问修饰符] interface 接口名[ : 基接口列表]
{
}
接口的访问修饰符为 public 和 internal,默认为 public
接口成员隐式具有 public访问修饰符,不能为接口成员添加任何访问修饰符。
5.5.2 接口的实现
5.5.3 接口的继承性
接口间可以进行多继承,两个基接口之间用逗号分隔。
5.5.4 多重接口实现
一个类可以实现多个接口
其类的头部如下所示:
public class Mobile : IUSB, IBuetooth
public class Mobile : Phone, IUsb, Ibluetooth
基类必须在所有基接口之前。
5.5.5 访问接口的成员
1.当类Mp3实现了IUsb后,我们可以通过MP3类的对象访问IUsb的成员,就好像是Mp3类的成员一样:
Mp3 m = new Mp3();
m.TransData(“计算机”, “MP3设备”);
2.也可以将Mp3对象转换成接口类型,然后用这个接口来访问方法:
Mp3 m = new Mp3();
IUsb iu = (IUsb)m;
iu.TransData(“计算机”, “MP3设备”);
5.5.6 抽象类与接口的比较
1.抽象类可以是完全实现的,也可以是部分实现的,也可以是完全不实现的。
接口的全部成员都没有实现。
2.派生类只能从单一的抽象类进行继承。
派生类可以继承多个基接口。
3.抽象类的抽象成员包含方法、属性、事件、索引器,非抽象成员可包括字段、构造函数等。
接口成员包含方法、属性、索引器、事件。
5.6 嵌套类、分布类与命名空间
5.6.1 嵌套类
在类的内部或结构的内部定义的类型成为嵌套类型。
嵌套类型也可以设置为五种类型中的一种,默认为private。
嵌套类实例化为对象之后,才能引用其成员,使用方法与类的普通成员使用基本相同。
5.6.2 分布类
分布类允许将类、结构、接口的定义拆分到两个或多个源文件中,让每个源文件只包含类型定义的一部分,编译时编译器自动把所有部分组合起来进行编译(加快程序设计的工作进度)。
分布类的规则:
1.同一类型的各个部分的所有分布类的定义都必须使用 partial 进行修饰。
2.如果任意部分是抽象的,则整个类型都被视为抽象的。密封也同理。
3.partial修饰符只能出现在紧靠关键字 class 、 struct 或 interface 前面的位置。
4.分布类各部分或各个源文件都可以独立引用类库,坚持“谁使用谁负责添加引用”的原则。
5.分布类的定义中允许使用嵌套的分布类。
5.6.3 命名空间
自定义命名空间:
namespace 命名空间名
{
}
第六章 集合、索引器与泛型
6.1 集合
6.1.1 集合概述
.NET Framework提供的常用集合包括 数组、列表、哈希表、字典、队列、堆栈等基本类型,还包括有序列表、双向链表和有序字典等派生集合类型。
6.1.2 ArrayList
ArrayList是一个可动态维护长度的集合,不限元素个数和数据类型。
Array和ArrayList的主要区别如下:
1.Array的大小是固定的,ArrayList的大小可根据需要自动扩充。
2.Array中一次只能获取或设置一个元素的值,而在ArrayList中允许添加、插入或移除某一范围的元素。
3.Array的下限可以自己定义,ArrayList的下限始终为零。
4.Array可以有多个维度,ArrayList始终是一维。
5.Array在System命名空间中,ArrayList位于System.Collections命名空间中。
添加元素的Add函数原型是 int Add(object value);
访问元素可以通过索引,ArrayList[index];
删除元素的两个函数是void Remove(object obj); void RemoveAt(int index); void Clear();
插入元素的函数是 void Insert(int index, object value); 后面元素的索引值会自动增加。
遍历元素可以用数组相似的方式 for(int i = 0; i < AIStudents.Count; i++) …
6.1.3 哈希表
哈希表(散列表)
创建哈希表对象的一般形式如下:
Hashtable 哈希表名 = new Hashtable( [哈希表长度] [,增长因子]);
其中,如果不指定哈希表长度,则默认容量为0,添加元素时重新分配按需自动增加,增长因子表示每调整一次增加容量多少倍,默认的增长因子为1.0。
6.1.4 栈和队列
创建: Stack 栈名 = new Stack(); Queue 队列名 = new Queue([队列长度] [, 增长因子]);
默认的增长因子为2.0
6.2 索引器
6.2.1 索引器的定义与使用
定义索引器的方式与定义属性有些相似,其一般形式如下:
[修饰符] 数据类型 this[索引类型 index]
{
get
{
}
set
{
}
}
索引器的使用:对象名[索引]
6.2.2 索引器与属性的比较
索引器与属性都是类的成员,语法上非常相似。
索引器一般用在自定义的集合类中,通过使用索引器来操作集合对象如同使用数组一样简单;
而属性可用于任何自定义类,它增强了类的字段成员的灵活性。
6.3 泛型
第七章 程序调试与异常处理
7.1 程序错误
7.1.1 程序错误分类
1.语法错误 2.逻辑错误 3.运行时错误
7.1.2 调试程序错误
7.2 程序的异常处理
7.2.1 异常的概念
所谓异常就是那些能影响程序正常执行的事件,而对这些事件的处理方法成为异常处理。
7.2.2 try-catch语句与异常处理
CLR本身引发的异常,例如溢出、数组越界、除数为0等。
为了能够对异常有效处理,C#提供了try-catch语句,格式如下:
try
{
语句块1 //可能引发的异常
}
catch (异常对象) // 捕获异常类对象
{
语句块2 // 实现异常处理
}