一、选择题(每小题2分，共20分) 1、C#是一种面向( )的语言。 A.机器 B.过程 C.对象 D.事物 2、在C#中，定义派生类时，指定其基类应使用的语句是( )。 A.Inherits B.: C.Class D.Overrides 3、类的以下特性中，可以用于方便地重用己有的代码和数据的是( )。 A.多态 B.封装 C.继承 D.抽象 4、在Array类中，可以对一维数组中的元素进行排序的方法是( )。 A.Sort() B.Clear() C.Copy() D.int.Parse() 5、将变量从字符串类型转换为数值类型可以使用的类型转换方法是( )。 A.Str() B.Cchar() C.CStr() D.int.Parse() 6、在C#中定义接口时，使用的关键字是( )。 A.interface B.: C.class D.overrides 7、以下说法正确的是( )。 A.接口可以实例化 B.类只能实现一个接口 C.接口的成员都必须是未实现的 D.接口的成员前面可以加访问修饰符 8、下列关于抽象类的说法错误的是( )。 A.抽象类可以实例化 B.抽象类可以包含抽象方法 C.抽象类可以包含抽象属性 D.抽象类可以引用派生类的实例 9.下列关于重载的说法，错误的是( )。 A.方法可以通过指定不同的参数个数重载 B.方法可以通过指定不同的参数类型重载 C.方法可以通过指定不同的参数传递方式重载 D.方法可以通过指定不同的返回值类型重载 10.关于虚方法实现多态，下列说法错误的是( )。 A.定义虚方法使用关键字virtual B.关键字virtual可以与override一起使用 C.虚方法是实现多态的一种应用形式 D.派生类是实现多态的一种应用形式二、简答题(每小题5分，共20分)二、简答题(每小题5分，共20分) l、简述private、protected、public修饰符的作用 答： 2、构造方法的特征和作用 答： 3、简述接口和抽象类的区别。 答： 4、什么是序列化和反序列化？ 答： 三、编码题(每小题20分，共60分)1、编写一个C#应用程序，该程序包括3个类：Monkey类、People类和主类Program类（20分） 要求： (1)Monkey类中有个构造方法：Monkey(String name),并且有个public void Speak()方法，在speak方法中输出“咿咿呀呀......”的信息。 (2)People类是Monkey类的子类，在People类调用Monkey的构造方法，重写方法Speak(),在Speak方法中输出“小样的，不错嘛！会说话了！”的信息。 (3)在People类中新增方法void Think(),在Think方法中输出“别说话！认真思考！”的信息。 (4)在主类Program的Main方法中创建Monkey与People类的对象类测试这2个类的功能。 2、接口和抽象类(20) 汽车租赁公司，出租汽车种类有客车、货车和皮卡三种，每辆汽车除了具有编号、名称、租金三个基本属性之外，客车有载客量，货车有载货量，皮卡则具有载客量和载货量。 实现思路： l)需要定义两个接口，一个抽象类car,三个类：PassengerCar、Truck、Pickup.. 2)抽象类汽车Car:属性有：编号No,名称：Name,租金Rent 3)接口A:定义载货量方法ZaiHuoMethod() 4)接口B:定义载客量方法ZaiKeMethod() 5)子类客车PassengerCar继承汽车租赁公司Car,特有属性：载客量ZaiKe。继承接口B. 6)子类货车Truck继承汽车租赁公司Car,特有属性：载客量ZaiHuo。继承接口A. 7)子类货车Pickup继承汽车租赁公司Car,特有属性：载客量ZaiKe。载客量ZaiHuo.继承接口A和B. 8)在主函数中分别实例化三种汽车，并输出汽车的相关信息。 3、编一个程序，定义类Student和它的成员(私有字段、属性和方法)（学号，姓名，年龄、成绩、和输出个人所有信息的方法），用类Student生成三个对象s1,s2,s3,给对象s1,s2,s3的成员赋值后，将对象添加到泛型List<Student>中，通过foreach循环遍历输出对象的所有信息。(20分)
第十三章综合项目--模拟打斗程序初级项目1.任务编号：2.任务名称：模拟一个打斗程序3.任务所属课程名称：类的定义、常用类、封装4.任务难度：C-简单5.任务描述：1)编写一个控制台程序，实现一个简单的战斗程序。 2)首先定义一个基类英雄(Hero) 属性：(名字Name、血量HP、蓝量MP,基础伤害下限BaseHurtLow,基础伤害上限BaseHurtHigh,基础防御下限BaseDefenseLow,基础防御上限Base DefenseHigh) 构造方法：默认属性：血量1000，蓝量800，基础伤害下限100，基础伤害上限300，基础防御下限0，基础防御上限100 方法：基础攻击Attack())基础防御Defense() 攻击伤害=攻击下限到攻击上限的一个随机值，攻击伤害应减去被攻击者的防御值 3)定义一个打斗(Battle)类，用于控制交战。 类中包涵有一个方法FightGo(Hero a,Hero b),主要作用是：a先开始攻击b一下，然后b攻击a一下，互相来回攻击直至某个对象生命值为0为止，每次攻击对方可以选择 基础攻击还是技能攻击，扣除的生命值是在自己Attacklow和AttackHigh之间取一个随机值。方法中显示每次来回打斗的信息，包括对方英雄名字，扣除的生命值及剩余 的生命值等。 在main方法中定义2个英雄Hero对象，执行FightGo方法，来完成一次战斗过程。6.提示 产生随机数可以参考Random类， 攻击进度控制System.Threading.Thread.Sleep(1000);/休眠1秒参考代码-初级先定义一个Hero类{hide}using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Lesson13_1 { //首先定义一个基类英雄（Hero) /// /// 英雄类 /// class Hero { //属性:(名字Name、血量HP、蓝量MP,基础伤害下限BaseHurtLow,基础伤害上限BaswHurtHigh,基础防御下限BaseDefenseLow,基础防御上限BaseDefenseHigh) public string Name { get; set; } public int HP { get; set; } public int MP { get; set; } public int BaseHurtLow { get; set; } public int BaseHurtHigh { get; set; } public int BaseDefenseLow { get; set; } public int BaseDefenseHigh { get; set; } //默认属性：血量1000，蓝量800，基础伤害下限100，基础伤害上限300，基础防御下限0，基础防御上限100 public Hero(string Name) { this.Name = Name; this.HP = 1000; this.MP = 800; this.BaseHurtLow = 100; this.BaseHurtHigh = 300; this.BaseDefenseLow = 0; this.BaseDefenseHigh = 100; } /// /// 基础攻击 /// /// 攻击对象 public int Attack(Hero other) { Random rd = new Random(); //攻击伤害=攻击下限到攻击上限的一个随机值，攻击伤害应该减去被攻击者的防御值 int attackHurt = rd.Next(BaseHurtLow, BaseHurtHigh); return attackHurt - other.Denfense(); } /// /// 基础防御 /// /// <returns>英雄的防御值</returns> public int Denfense() { Random rd = new Random(); return rd.Next(BaseDefenseLow, BaseDefenseHigh); } } } {/hide}再定义一个Battle类{hide}using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Lesson13_1 { /// /// 打斗类 /// class Battle { public void FightGo(Hero a,Hero b) { Console.WriteLine("***************************************************************"); Console.WriteLine("************************战斗开始*******************************"); Console.WriteLine("***************************************************************"); int count = 1; while (true) { Console.WriteLine("-----------------------第"+count+"回合----------------------"); count++; if (a.HP > 0 && b.HP > 0) { System.Threading.Thread.Sleep(1000);//没有这句会出现大量的重复值 //a向b发动攻击 Console.WriteLine("{0}向{1}发动了攻击！", a.Name, b.Name); int hurtNum = a.Attack(b); b.HP -= hurtNum; Console.WriteLine("此次攻击造成了{0}点伤害，此时{1}还剩{2}点血", hurtNum, b.Name, b.HP); if (b.HP > 0) { System.Threading.Thread.Sleep(1000);//没有这句会出现大量的重复值 //b向a发动攻击 Console.WriteLine("{0}发动反攻！", b.Name); int hurtNum2 = b.Attack(a); a.HP -= hurtNum2; Console.WriteLine("此次攻击造成了{0}点伤害，此时{1}还剩{2}点血", hurtNum2, a.Name, a.HP); } else { Console.WriteLine("{0}已战死",b.Name); break;//循环结束 } } else { Console.WriteLine("{0}已战死", a.Name); break;//循环结束 } } } } } {/hide}主程序定义两个Hero对象{hide}using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Lesson13_1 { class Program { static void Main(string[] args) { //定义两个英雄Hero对象，执行FightGo方法，来完成一次战斗 Hero a = new Hero("李元芳"); Hero b = new Hero("孙悟空"); Battle bat = new Battle(); bat.FightGo(a, b); } } }{/hide}中级项目1.任务编号：2.任务名称：模拟一个打斗程序3.任务所属课程名称：类的定义、常用类、封装、继承、多态4.任务难度：B-适中5.任务描述：1)编写一个控制台程序，实现一个简单的战斗程序。 2)首先定义一个基类英雄(Hero) 属性:(名字Name、血量HP、蓝量MP,基础伤害下限BaseHurtLow,基础伤害上限BaseHurtHigh,基础防御下限BaseDefenseLow,基础防御上限BaseDefenseHigh) 构造方法：默认属性：血量1000，蓝量800，基础伤害下限100，基础伤害上限300，基础防御下限0，基础防御上限100 也可以用户自定义属性： 方法：基础攻击Attack() 基础防御Defense() 攻击伤害=攻击下限到攻击上限的一个随机值 3)再定义三个职业继承英雄类 战士(Soldier): 属性：（技能SkillName,技能伤害下限SkillHurtLow,技能伤害上限SkillHurtHigh,技能消耗蓝量SkillMP) 构造方法：战士构造方法中基础血量+300，蓝量-200，防御+50 方法：重写父类攻击方法Attack() 用户可选择发动物理攻击或技能攻击 物理攻击：攻击伤害=攻击者基础攻击值-被攻击者基础防御 技能攻击：攻击伤害=攻击者技能攻击值-被攻击者基础防御 注意：技能伤害消耗相应蓝值，蓝值不够不能发动技能攻击，只能发动物理攻击 射手(Shooter): 属性：（技能SkillName,技能伤害下限SkillHurtLow,技能伤害上限SkillHurtHigh,技能消耗蓝量SkillMP) 构造方法：射手构造方法中基础血量-300，攻击+120，防御-20 方法：技能伤害SkillAttack() 刺客(Assassin): 属性：（技能SkillName,技能伤害下限SkillHurtLow,技能伤害上限SkillHurtHigh,技能消耗蓝量SkillMP) 构造方法：刺客构造方法中基础伤害+120，基础血量-100，防御-20 方法：技能伤害SkillAttack() 同时定义构造函数用于初始化这些信息。参考代码-中级先定义一个Hero类,添加技能相关的属性，在Attack的方法中添加技能攻击{hide}using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Lesson13 { //首先定义一个基类英雄（Hero) /// /// 英雄类 /// class Hero { //属性:(名字Name、血量HP、蓝量MP,基础伤害下限BaseHurtLow,基础伤害上限BaswHurtHigh,基础防御下限BaseDefenseLow,基础防御上限BaseDefenseHigh) public string Name { get; set; } public int HP { get; set; } public int MP { get; set; } public int BaseHurtLow { get; set; } public int BaseHurtHigh { get; set; } public int BaseDefenseLow { get; set; } public int BaseDefenseHigh { get; set; } //技能SkillName,技能伤害下限SkillHurtLow,技能伤害上限SkillHurtHigh,技能消耗蓝量SkillMP public string SkillName { get; set; } public int SkillHurtLow { get; set; } public int SkillHurtHigh { get; set; } public int SkillMP { get; set; } //默认属性：血量1000，蓝量800，基础伤害下限100，基础伤害上限300，基础防御下限0，基础防御上限100 public Hero(string Name,string SkillName) { this.Name = Name; this.HP = 1000; this.MP = 800; this.BaseHurtLow = 100; this.BaseHurtHigh = 300; this.BaseDefenseLow = 0; this.BaseDefenseHigh = 100; this.SkillName = SkillName; this.SkillHurtLow = 100; this.SkillHurtHigh = 300; this.SkillMP = 200; } /* /// /// 基础攻击 /// /// 攻击对象 public virtual int Attack(Hero other)//定义为虚方法 { Random rd = new Random(); //攻击伤害=攻击下限到攻击上限的一个随机值，攻击伤害应该减去被攻击者的防御值 int attackHurt = rd.Next(BaseHurtLow, BaseHurtHigh); return attackHurt - other.Denfense(); } */ /// /// 基础防御 /// /// <returns>英雄的防御值</returns> public int Denfense() { Random rd = new Random(); return rd.Next(BaseDefenseLow, BaseDefenseHigh); } /// /// 攻击 /// /// 攻击对象 /// <returns></returns> public int Attack(Hero other) { //用户可选择发动物理攻击或技能攻击 //普通攻击 Random rd = new Random(); //攻击伤害=攻击下限到攻击上限的一个随机值，攻击伤害应该减去被攻击者的防御值 int attackHurt = rd.Next(BaseHurtLow, BaseHurtHigh); Console.WriteLine("请选择你要发动的攻击：1、物理攻击 2、技能攻击"); string choose = Console.ReadLine(); if (choose=="1") { return attackHurt; } else if(choose == "2") { //技能攻击：攻击伤害=攻击者技能攻击值-被攻击者基础防御 Random rdS = new Random(); if (this.MP>=SkillMP) { int skillHurt = rdS.Next(SkillHurtLow, SkillHurtHigh) - other.Denfense(); this.MP -= SkillMP; Console.WriteLine("{0}发动了{1}技能造成了{2}点伤害", this.Name, this.SkillName, skillHurt); return skillHurt; } else { Console.WriteLine("蓝量不足，发动技能失败，默认选择物理攻击"); return attackHurt; } } else { Console.WriteLine("发动技能失误，默认选择物理攻击"); return attackHurt; } } } }{/hide}添加3个职业类{hide}{tabs}{tabs-pane label="战士类"}using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Lesson13 { class Soldier:Hero { //战士构造方法中基础血量+300，蓝量-200，防御+50 public Soldier(string Name, string SkillName) :base(Name, SkillName) { base.HP +=300; base.MP -=200; base.BaseDefenseLow += 50; base.BaseDefenseHigh += 50; base.SkillName = SkillName; base.SkillHurtLow += 20; base.SkillHurtHigh += 50; base.SkillMP -= 20; } } } {/tabs-pane}{tabs-pane label="射手类"}using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Lesson13 { class Shooter:Hero { //射手构造方法中基础血量-300，攻击+120，防御-20 public Shooter(string Name, string SkillName) : base(Name, SkillName) { base.HP -= 300; base.BaseHurtLow += 120; base.BaseHurtHigh += 120; base.BaseDefenseLow -= 20; base.BaseDefenseHigh -= 20; base.SkillName = SkillName; base.SkillHurtLow += 20; base.SkillHurtHigh += 50; base.SkillMP -= 20; } } } {/tabs-pane}{tabs-pane label="刺客类"}using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Lesson13 { class Assassin:Hero { //刺客构造方法中基础伤害+120，基础血量-100，防御-20 public Assassin(string Name, string SkillName) : base(Name,SkillName) { base.HP -= 100; base.BaseHurtLow += 120; base.BaseHurtHigh += 120; base.BaseDefenseLow -= 20; base.BaseDefenseHigh -= 20; base.SkillName = SkillName; base.SkillHurtLow += 20; base.SkillHurtHigh += 50; base.SkillMP -= 20; } } } {/tabs-pane}{/tabs}{/hide}添加一个Battle类{hide}using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Lesson13 { /// /// 打斗类 /// class Battle { public void FightGo(Hero a, Hero b) { Console.WriteLine("***************************************************************"); Console.WriteLine("************************战斗开始*******************************"); Console.WriteLine("***************************************************************"); int count = 1; while (true) { Console.WriteLine("-----------------------第" + count + "回合----------------------"); count++; if (a.HP > 0 && b.HP > 0) { System.Threading.Thread.Sleep(1000);//没有这句会出现大量的重复值 //a向b发动攻击 Console.WriteLine("{0}向{1}发动了攻击！", a.Name, b.Name); int hurtNum = a.Attack(b); b.HP -= hurtNum; Console.WriteLine("此次攻击造成了{0}点伤害，此时{1}还剩{2}点血", hurtNum, b.Name, b.HP); if (b.HP > 0) { System.Threading.Thread.Sleep(1000);//没有这句会出现大量的重复值 //b向a发动攻击 Console.WriteLine("{0}发动反攻！", b.Name); int hurtNum2 = b.Attack(a); a.HP -= hurtNum2; Console.WriteLine("此次攻击造成了{0}点伤害，此时{1}还剩{2}点血", hurtNum2, a.Name, a.HP); } else { Console.WriteLine("{0}已战死", b.Name); break;//循环结束 } } else { Console.WriteLine("{0}已战死", a.Name); break;//循环结束 } } } } }{/hide}主程序添加两个职业类及技能名{hide}using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Lesson13 { class Program { static void Main(string[] args) { //定义两个英雄Hero对象，执行FightGo方法，来完成一次战斗 Hero a = new Shooter("李元芳", "无间刃风"); Hero b = new Soldier("孙悟空", "如意金箍"); Battle bat = new Battle(); bat.FightGo(a, b); } } }{/hide}
第十二章文件处理目标了解System.IO命名空间文件和目录的常用操作方法使用文件流读写文本文件使用文件流读写二进制文件掌握打开文件、保存文件对话框的使用序列化和反序列化System.IO命名空间对文件操作System.lo命名空间操作各种流类数据System.Text命名空间关于字符编码的类File类文件操作静态类方法描述Create(string filePath)在指定路径下创建指定名称的文件Copy(string sourceFile,string desFile)按指定路径将源文件中的内容复制到目标文件中，如果目标文件不存在将新建目标文件Delete(string filePath)删除指定路径的文件Exists(string filePath)验证指定路径的文件是否存在Move(string sourceFile,string desFile)将指定文件移动到一个新的路径实例using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.IO;//读写文件流操作 namespace Lesson12_1 { class Program { static void Main(string[] args) { //File类内包含用于处理文件的静态方法 if (!File.Exists(@"D:\aa.txt")) { File.Create(@"D:\aa.txt"); } else { File.Copy(@"D:\aa.txt", @"D:\bb.txt"); } File.Delete(@"D:\aa.txt"); } } }using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.IO; namespace Lesson12_2 { class Program { static void Main(string[] args) { //Directory类包含了处理目录的静态方法 Directory.CreateDirectory("@D:/测试目录"); } } }Directory类目录（文件夹）操作静态类方法描述CreateDirectory(string path)创建目录Dele(string path[,bool recursive])删除指定的目录，如果第二个参数为true则同时删除该目录下的所有文件和子目录Exists(string path)测试目录是否存在GetCurrentDirectory()获得应用程序的当前工作目录GetDirectories(string path)返回代表子目录的字符串数组GetFiles(string path)以字符串数组形式返回指定目录中的文件的名称Move(string sourcePath,string desPath)将目录及其内容移到指定的新位置读写文本文件文件流FileStream构造方法FileStream(filePath,FileMode,[FileAccess],[FileShare])filePath是string类型其余3个是枚举类流读取对象StreamWriter类流写入对象Write()WriteLine()Close()StreamReader类流读取对象ReadLine()ReadToEnd()Close()方法二进制文件的读写BinaryReader类BinaryWriter类实例using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.IO; namespace Lesson12_3 { class Program { static void Main(string[] args) { //1、 FileStream fs = new FileStream(@"D:\二进制.data",FileMode.Create); //2、二进制写入对象 BinaryWriter bw = new BinaryWriter(fs); //3、写入二进制文件 for (int i = 0; i < 10; i++) { bw.Write(i); } Console.WriteLine("已写入"); //4、 bw.Close(); //5、 fs.Close(); Console.WriteLine("=================================读取二进制文件============================================="); //1、 FileStream fr = new FileStream(@"D:\二进制.data", FileMode.Open,FileAccess.Read); //2、二进制读取对象 BinaryReader br = new BinaryReader(fr); //3、读取二进制文件 try { while (true) { int num = br.ReadInt32(); Console.WriteLine(num); } } catch (EndOfStreamException ex) { Console.WriteLine("读取完成"); } //4、 bw.Close(); //5、 fs.Close(); } } }复制图片到指定目录using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.IO; namespace Lesson12_4 { class Program { static void Main(string[] args) { //读取图片的二进制信息 FileStream fs = new FileStream(@"D:\Desktop\示例图片.jpg", FileMode.Open,FileAccess.Read); BinaryReader br = new BinaryReader(fs); //读取文件信息 byte[] b = br.ReadBytes((int)fs.Length); br.Close(); fs.Close(); //复制图片--其实就是在另一个路径写入图片信息 FileStream fsWrite = new FileStream(@"E:\示例图片1.jpg", FileMode.Create); BinaryWriter bw = new BinaryWriter(fsWrite); //将读出的字节数组写入到文件 bw.Write(b); Console.WriteLine("图片复制成功"); bw.Close(); fsWrite.Close(); } } }序列化和反序列化序列化将 对象 的状态存储到特定的文件中Serialize()反序列化是序列化的逆向过程，也就是将文件里保存的数据还原为对象Deserialize()步骤引用命名空间using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters; using System.Runtime.Serialization.Formatters.Binary;[Serializable]必须写在类定义前面，表示后面的类可以被序列化实例序列化是面向对象的所以先创建一个类using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Lesson12_5 { [Serializable]//[Serializable]必须写在类定义前面，表示后面的类可以被序列化 class Student { public int StuId { get; set; } public string Name { get; set; } public int Age { get; set; } public string Sex { get; set; } public Student(int StuId, string Name,int Age,string Sex) { this.StuId = StuId; this.Name = Name; this.Age = Age; this.Sex = Sex; } } }然后对实例化这个类并进行序列化和反序列化操作using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.IO; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters; using System.Runtime.Serialization.Formatters.Binary; namespace Lesson12_5 { class Program { static void Main(string[] args) { Student stu = new Student(1,"fsy",29,"Man"); BinaryFormatter bf = new BinaryFormatter(); FileStream fs = new FileStream(@"D:\MyFile.bin", FileMode.Create, FileAccess.Write); //对象序列化 bf.Serialize(fs,stu); fs.Close(); Console.WriteLine("序列化成功"); Console.WriteLine("=============反序列化============"); //BinaryFormatter bf = new BinaryFormatter(); FileStream fsReader = new FileStream(@"D:\MyFile.bin", FileMode.Open, FileAccess.Read); //反序列化 Student stu1= bf.Deserialize(fsReader) as Student; fsReader.Close(); Console.WriteLine("学号{0}，姓名{1}，年龄{2}，性别{3}",stu1.StuId,stu1.Name,stu1.Age,stu1.Sex); } } }总结File类静态对象实现对文件的创建、拷贝、移动和删除等操作Directory类静态对象实现对目录（文件夹）的操作文件流对象FileStream对象创建该对象时需要指定操作文件的路径、文件的打开方式文件读写权和文件访问方式（可选）流读写对象StreamReader是流读取对StreamWriter是文件写入对象。二进制文件的读写BinaryReaderBinaryWriter序列化和反序列化序列化是将对象的状态存储到特定的文件中。反序列化是将存储在文件中的数据重新构建为对象类对象是否可被序列化，关键是在类的头部添加[Serializable]关键字
第十一章调试与异常目标理解如何调试应用程序和排除错误掌握如何测试C#应用程序在程序中进行错误捕获和错误处理调试必要性在不熟应用程序前必须先对其进行调试在事物处理过程中，系统显示错误信息错误类型语法错误逻辑错误运行时错误调试过程观察程序运行时行为跟踪变量的值确定语义错误的位置VS中的操作步骤合理设置断点鼠标右键F9运行DebugF5F10单步执行VS.NET调试工具“局部变量”窗口“监视”窗口“即时”窗口“快速监视”窗口异常C#中的异常处理语句异常是由try语句来处理的try语句提供了一种机制来捕捉块执行过程中发生的异常C提供了3种异常处理结构：try-catchtry-catch-finallytry-finallytry块：try块监视可能抛出异常的语句。 try { //statements that may cause an exception }·try块管理包含在它内部的语句，定义与它相关的异常处理程序的范围。·try块必须至少有一个catch块。C#引发异常有以下两种方式使用显式throwi语句来引发异常控制权无条件转到处理异常的部分代码使用语句或表达式在执行过程中激发了某个异常的条件，使得操作无法正常结束，从而引发异常Try......Catch......Finally I/O设备异常 try { //程序代码 } catch(IOException E) { //错误处理代码 }System.Exception可以是系统中任何一种异常Try/catch/finally异常Catch可以多重Finally块一般清理内存用Try块中最后执行System.Exception属性含义Message描述当前异常对象的字符串Source引必当前异常对象的程序或对象名称StackTrace发异常时调用堆栈上的帧的字符串表示InnerException表示引发当前异常的内部异常对象常用异常类ArithmeticException数学运算、类型转换异常类InvalidCastException不正确转型异常。例如String转Decimal操作。IndexOutOfRangeException数组访问越界异常。NullReferenceException空引用对象异常。实例using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Collections; namespace Lesson11_2 { class Program { static void Main(string[] args) { ArrayList list = new ArrayList(); try { //程序尝试执行的代码 list.Add(0); list.Add(1); list.Add("2"); list.Add(3); list.Add(4); Console.WriteLine(list[7]); foreach (int item in list) { Console.WriteLine(item); } } catch (IndexOutOfRangeException indexOut)//下标越界异常 { Console.WriteLine(indexOut.Message); } catch (Exception ex)//想要捕获的异常类型 { //错误处理代码 Console.WriteLine(ex.Message);//输出异常的信息 } finally { //不管有没有出现异常或者异常有没有被处理，都会最终执行的代码 Console.WriteLine("程序终止！"); } } } }Throw语句自定义异常当开发人员需要提供更为广泛的信息，或需要程序具有特殊功能时，就可以定义自定义异常。首先要创建一个自定义异常类，该类必须直接或间接派生自System.ApplicationException。using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Lesson11_3 { /// /// 除数不能为0为异常 /// class MyCustomException:ApplicationException { public MyCustomException() { } public MyCustomException(string message) : base(message) { } } }using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Lesson11_3 { class Program { static void Main(string[] args) { Console.WriteLine("请输入你的除数"); int divisor = int.Parse(Console.ReadLine()); try { if (divisor==0) { throw new MyCustomException("除数不能为0"); } } catch (MyCustomException ex) { //throw ex; Console.WriteLine("自定义异常信息"+ex.Message); } } } }注意事项请勿将try/catch块处于控制流。用户只能处理catch异常。不得声明空catch块。避免在catch块内嵌套try/catch只有使用finally块才能从try语句中释放资源。总结调试搜寻和消除应用程序中的错误的过程。语法错误表示编译器无法理解代码。“局部变量”窗口允许用户监控当前方法中所有局部变量的值。异常当应用程序遇到运行时错误，就会引发异常。C#中的所有异常都派生自System.Exception类。
第十章集合与泛型目标使用System.Array操作数组集合使用System.ArrayListi对象使用System.Hashtable对象理解泛型集合类List对象掌握Dictionary<TKey,TValue>掌握Lambda表达式IComparable接口的应用泛型接口IComparable接☐IComparer接口{dotted startColor="#ff6c6c" endColor="#1989fa"/}System.Array抽象的基类提供Createlnstance方法创建数组可以是多维的下标可设置System.Array的属性和方法属性描述Length得到数组所有维元素总个数的属性实例方法描述Copyto()将一个一维数组中的所有元素复制到另一个一维数组中GetLength()返回指定维的元素个数GetVaule通过索引返回指定元素的值SetVaule将数组中的指定元素设为指定值静态方法描述BinarySearch()使用二进制搜索方法搜索一维已排序数组中的某个值Clear()将数组中一组元素设为0或nullCopy()将数组中的一部分元素复制到另一个数组中CreateInstance()初始化Array类的实例Indexof()返回给定值在一维数组中首次出现的位置索引Last Indexof()返回给定值在一维数组中最后一次出现的位置索引Reverse()反转给定一维数组中元素的顺序Resize()将数组的大小更改为指定的新大小Sort()将数组中的元素进行排序，只能对一维数组从小到大排序实例 static void Main(string[] args) { //系统类可以按F12看定义 //用Array(抽象类)创建数组 Array arr = Array.CreateInstance(typeof(int),5);//创建int类型长度为5的数组 arr.SetValue(89, 0);//为数组元素设置值 arr.SetValue(95, 1); Console.WriteLine(arr.Length); foreach (int item in arr) { Console.WriteLine(item); } for (int i = 0; i < arr.Length; i++) { Console.WriteLine("数组中第{0}个元素是：{1}",i+1,arr.GetValue(i)); } }{dotted startColor="#ff6c6c" endColor="#1989fa"/}集合System.Collectionsi命名空间ArrayList类Hashtable类集合-ArrayList类容量可以根据需要动态扩展。通过设置ArrayList..Capacityl的值可以执行重新分配内存和复制元素等操作批量操作提供的方法在某个时间追加、插入或移出一组元素一维下标不可设置实例 static void Main(string[] args) { //实例化一个集合 ArrayList list = new ArrayList(4); list.Add(10); list.Add("FSY"); list.Add(101.101); People pl = new People(); list.Add(pl); foreach (var item in list) { Console.WriteLine(item); } list.Add("1"); //移除集合中的元素，集合容量不变 list.Remove(10); //如果添加元素时添加的个数大于容量时，容量会自动增加一倍 Console.WriteLine("集合的个数是"+list.Count); Console.WriteLine("集合的容量是"+list.Capacity); //将集合容量设置为集合的实际个数 list.TrimToSize(); Console.WriteLine("集合的个数是" + list.Count); Console.WriteLine("集合的容量是" + list.Capacity); }集合-Hashtable类将数据作为一组键值对来存储键索引器不可重复属性描述Count该属性用于获取哈希表中键值对的数量方法描述Add()将一个键值对添加到哈希表中ContainKey()测试键是否已经存在Remove()根据键将对应的键值对从哈希表移除实例 static void Main(string[] args) { Hashtable ht = new Hashtable(); ht.Add(1,"FSY"); ht.Add(2, "ZLY"); ht.Add("FSY", "ZLY"); Console.WriteLine("有{0}个元素",ht.Count); Console.WriteLine(ht.ContainsKey("FSY")); if (ht.ContainsKey(1)==true) { Console.WriteLine(ht[1]); } //集合没有类型限制，很容易出现类型访问错误，类型是不安全的 foreach (var item in ht.Keys) { Console.WriteLine(ht[item]); } }泛型集合明确指定放入集合中对象的数据类型优点类型安全使用泛型集合编译器会在编译期间检查要放入集合的对象的数据类型，如果发现不是某种特定的类型就会报错提高性能存取数据时不会发生类型转换，特别是存取值类型时不会发生装箱和拆箱操作System.Collections.Generici命名空间 List<T> Dictionary<K,V>List语法泛型集合类<数据类型>实例名=new泛型集合类<数据类型>()添加和访问元素、插入和删除元素、清空集合、把元素复制到数组中，而且可以搜索和转换元素、使元素逆序等高级操作FindAll()方法检索ForEach()方法可以使用委托对集合的每一个成员进行操作实例 class Program { static void Main(string[] args) { //泛型集合 //定义一个Student类型的泛型集合 List<Student> list = new List<Student>(); //实例化4个学生对象 Student stu1 = new Student("张三", 1); Student stu2 = new Student("李四", 2); Student stu3 = new Student("王五", 3); Student stu4 = new Student("赵六", 4); //向泛型集合添加元素 list.Add(stu1); list.Add(stu2); list.Add(stu3); list.Add(stu4); Console.WriteLine(list.Count); foreach (Student item in list) { Console.WriteLine("学号：{0}，姓名：{1}",item.StuId,item.Name); } //效果与foreach一致 list.ForEach(delegate (Student s) { Console.WriteLine("学号：{0}，姓名：{1}", s.StuId,s.Name); }); //在泛型集合中查找所有学号小于3的学生 List<Student> listFind = list.FindAll(delegate (Student s) { if (s.StuId < 3) { return true; } else { return false; } }); listFind.ForEach(delegate (Student s) { Console.WriteLine("学号：{0}，姓名：{1}", s.StuId, s.Name); }); }Dictionary<K,V>语法Dictionary<数据类型，数据类型>实例名=new Dictionary<数据类型，数据类型>();Dictionary<TKey,Value>类的功能与HashTable类类似，也是通过键值对来存储元素。TKey表示键的数据类型TValue表示值的数据类型。实例 class Program { static void Main(string[] args) { //泛型集合 //定义一个Student类型的泛型集合 List<Student> list = new List<Student>(); //实例化4个学生对象 Student stu1 = new Student("张三", 1); Student stu2 = new Student("李四", 2); Student stu3 = new Student("王五", 3); Student stu4 = new Student("赵六", 4); //向字典类添加元素 dicStu.Add(stu1.StuId, stu1); dicStu.Add(stu2.StuId, stu2); dicStu.Add(stu3.StuId, stu3); dicStu.Add(stu4.StuId, stu4); //dicStu.Add(stu4.Name,stu4);错，数据类型必须保持一致 foreach (int item in dicStu.Keys) { Console.WriteLine(dicStu[item].Name); } }对象与集合初始化器集合初始化器用来初始化一个集合，它由一系列元素组成，并封闭于“{”和“}”标记内//对象初始化器 Student s1 = new Student{SId=101, SName="张三"}; Student s2 = new Student{SId=102, SName="李四"}; //集合初始化器 List<Student> lstStu = new List<Student> {s1,s2};实例 static void Main(string[] args) { //实例化学生对象 //对象初始化器 Student stu1 = new Student { SId = 1, Name = "FSY" }; Student stu2 = new Student { SId = 2, Name = "YSF" }; //集合初始化器 List<Student> list = new List<Student> { stu1, stu2 }; foreach (Student item in list) { Console.WriteLine("学号："+item.SId+",姓名"+item.Name); } }Lambda表达式s是一个匿名函数，它可以包含表达式和语句，并且可用于创建委托或飙到式目录树类型基本形式（inputparameter）=>expression=>读作“goes to”Lambda语句（inputparameter）=>{statement;};实例 static void Main(string[] args) { //Lambda表达式 //语法：参数=>表达式 int[] arr = { 436, 67, 78, 9, 3, 57, 2, 7, 9, 1 }; //查找数组中奇数的个数 Console.WriteLine(arr.Count(n => n % 2 == 1)); /* public static bool JiSuan(int n) { if (n %== 1) { return truwe; } else { return false; } } */ }总结Array类Createlnstance方法来创建Array对象属于System命名空间集合用于管理在运行时动态创建的元素项集合ArrayList类可以批量操作Hashtable类键值对System.Collections命名空间泛型集合ListDictionary<Tkey,Tvalue>类型安全属于System.Collections.Generic命名空间Lambda表达式一种更纯粹的匿名方法
第九章常用类目标{dotted startColor="#ff6c6c" endColor="#1989fa"/}Math类为三角函数、对数函数和其他通用数学函数提供常数和静态方法对数字变量提供操作方法系统类，只需会操作 class Program { static void Main(string[] args) { //Math类是一个静态类 Console.WriteLine(Math.PI);//圆周率 Console.WriteLine(Math.Abs(-2));//返回自然数的绝对值 Console.WriteLine(Math.Acos(0.5));//返回余弦值为指定数字的角度（单位为弧度） Console.WriteLine(180*Math.Acos(0.5)/Math.PI);//返回余弦值为指定数字的角度 Console.WriteLine(Math.Floor(6.7));//对小数向下取整 Console.WriteLine(Math.Round(6.7));//返回四舍五入的值 Console.WriteLine(Math.Sqrt(9));//返回指定数的平方根 Console.WriteLine(Math.Pow(3, 2));//求一个数的指定次幂 } }{dotted startColor="#ff6c6c" endColor="#1989fa"/}Random类命名空间：System伪随机生成器伪随机数是以相同的概率从一组有限的数字中选取的。所选数字并不具有完全的随机性，因为它们是一种确定的数学算法选择的，但是从实用的角度而言，其随机程度已经够用。class Program { static void Main(string[] args) { //Random类是用来产生随机数的一个系统类 // 第一种实例化 Random rd = new Random(); Console.WriteLine(rd.Next());//返回一个随机数 Console.WriteLine(rd.Next(10));//返回一个指定最大值的随机数 Console.WriteLine(rd.Next(100,200));//返回一个指定范围的随机数 //第二种实例化 Random rd2 = new Random(6); for (int i = 0; i < 10; i++) { Console.Write(rd2.Next(100,200)+" "); } } }{dotted startColor="#ff6c6c" endColor="#1989fa"/}DateTime类一个结构体，它表示时间上的一刻，通常以日期和当天的时间表示构造函数Datetime静态属性NowToday static void Main(string[] args) { //DateTime是表示时间的结构体 Console.WriteLine(DateTime.IsLeapYear(2024)); //年份是否是闰年 Console.WriteLine(DateTime.Now);//获取此计算机上的当前时间 Console.WriteLine(DateTime.Now.AddYears(3));//在当前时间的基础上加上相应的日期 Console.WriteLine(DateTime.Today);//获取此计算机上的当前日期，时间为0 Console.WriteLine(DateTime.Today.ToLongDateString());//获取此计算机上的当前日期 Console.WriteLine(DateTime.Today.ToShortDateString());//获取此计算机上的当前日期 Console.WriteLine(DateTime.Now.ToLongTimeString());//获取此计算机上的当前时间，时分秒 Console.WriteLine(DateTime.Now.ToShortTimeString());//获取此计算机上的当前时间，时分 Console.WriteLine(DateTime.Now.ToString());//获取此计算机上的当前时间 Console.WriteLine(DateTime.Now.ToString());//获取当地的时间 }{dotted startColor="#ff6c6c" endColor="#1989fa"/}String类和StringBUilder类System.String类具有不变性和string关键字对应可以使用“+”连接多个字符串可以使用索引器提取字符频繁的插入、删除或替换操作就会明显的降低性能StringBuilder类具有可变性只能进行增、删、改操作Length,属性获取字符串的实际长度，Capacity属性获取字符串占据的内存容量实例 static void Main(string[] args) { //String和StringBuiler都是和字符串有关的类 //String类 string str = "你好," + "我是FSY,我是FSY,我是FSY"; Console.WriteLine(str); Console.WriteLine(str.Length);//计算字符串的长度，空格也算 Console.WriteLine(str.Remove(3,5));//从0开始计算，删除后面的字符 Console.WriteLine(str.Replace("F", "Y"));//替换指定字符 Console.WriteLine(str.Insert(3,"1"));//插入字符的位置及字符 Console.WriteLine(str.Substring(3,5));//从字符串中提取一些字符 Console.WriteLine("======================================================"); //按照指定规则分割字符串 string[] arr = str.Split(','); //遍历输出数组中的元素 foreach (string item in arr) { Console.WriteLine(item+"*"); } Console.WriteLine("========================================================"); //StringBuilder具有可变性 StringBuilder sb = new StringBuilder("Hello World"); Console.WriteLine(sb.Capacity);//字符串在内存中的容量 sb.Append("!你好，世界！");//在字符串后追加内容 Console.WriteLine(sb); Console.WriteLine(sb.Capacity);//字符串在内存中的容量 sb.Remove(3, 5);//将指定范围的字符从此实例中移除 Console.WriteLine(sb); }{dotted startColor="#ff6c6c" endColor="#1989fa"/}正则表达式引入System.Text.RegularExpressionsi命名空间Regex包含了正则表达式，以及使用正则表达式的各种方法。MathchCollction包含了一个正则表达式找到的所有匹配项。Match包含了一次匹配中所有匹配的文本。GroupCollection包含了一次匹配中的所有分组。Group包含了一个分组集合中一个组的细节。CaptureCollection包含一个组的所有Capture对象。Capture返回组内一次捕获所匹配的字符串。Regex类构造方法Regex(string pattern);Regex(string pattern,RegexOptions options);标志描述IgnoreCase忽略大小写，默认是区分大小写的None不设定标志，这是默认选项MultiLine指定了^和$可以匹配行的开头和结尾，以及字符串的开头和结尾。也就是说，使用换行符分隔，在每一行都能得到不同的匹配。但“.”仍然不匹配换行符IsMatch()方法实例方法New regex静态方法Regex.IsMatch实例 class Program { static void Main(string[] args) { //第一种：创建正则表达式对象 Regex rg = new Regex("ABC"); string str = "there is much ABC"; //使用IsMatch方法对字符串进行匹配 Console.WriteLine(rg.IsMatch(str)); //第二种：创建正则表达式对象 Regex reg = new Regex("ABC", RegexOptions.IgnoreCase);//不区分大小写 string str1 = "there is much AbC"; Console.WriteLine(reg.IsMatch(str1)); }Replace()方法实例方法New regex静态方法Regex.Replace实例Console.WriteLine(Regex.Replace("舔狗得house", "得", "不得"));Split()方法静态方法public static string[]Split(string input,string pattern)public static string[]Split(string input,string pattern,RegexOptions options)实例方法 string[] strArr = Regex.Split("绿色生态，绿色生活，铜绿，人生赢家", "绿"); foreach (var item in strArr) { Console.WriteLine(item); }{dotted startColor="#ff6c6c" endColor="#1989fa"/}MathchCollction类Match类和MathchCollction类利用正则表达式进行匹配时往往匹配成功的次数不止1次，如果想知道每一个成功匹配的细节，则需要用Match类和MatchCollection类。Match类表示一次成功的匹配，MatchCollection类是一个Match对象的集合。我们可以使用Regex类的Match()方法来得到一个Match对象或者用Matchs()方法来得到一个MatchCollection对象C#正则表达式匹配字符之含义1、正则表达式的作用：用来描述字符串的特征。2、各个匹配字符的含义：, :表示除\n以外的单个字符 [] :表示在字符数组[门中罗列出来的字符任意取单个 | :表示”或"的意思 () :表示改变优先级或"提取组" * :限定前面的表达式出现0次或多次 + :限定前面的表达式出现1次或多次 ? :限定前面的表达式出现0次或1次 ^ :表示以表达式开头(例:^http表示字符串以"http"开头) $ :表示以表达式结尾(例:com$表示字符串以"com"结尾) \d :小写\d表示0-9之间的数字 \D :大写\D表示除了0-9之外的字符 \w :写\w表示[a-zA-Z0-9] \W :大写\W表示除了[a-zA-Z0-9]之外的字符 \s :小写\s表示非可见字符(如空格、tab、\r\n..........) \S :大写\S表示除了非可见字符之外的字符实例 string str3="a sailor went to sea to set,to see what he could see"; MatchCollection mc = Regex.Matches(str3,"se\\w");//\是分隔符，\w是一个字符 Console.WriteLine(mc.Count); foreach (Match item in mc) { Console.WriteLine(item); } //验证手机号 string phoneNum = "^1[0-9]{10}$";//手机号的规律 string tel = Console.ReadLine(); //判断用户输入的数字是不是手机号 if (Regex.IsMatch(tel,phoneNum)) { Console.WriteLine("是一个手机号"); } else { Console.WriteLine("随便了"); }总结掌握Math类及方法的使用掌握Randoma类及方法的使用掌握DateTime类及方法的使用System.String类的对象具有不变性System.Text.StringBuilder类的对象的内容可以改变Regex类可用正则表达式处理复杂的字符串问题
一、选择题(每空2分，共10分)1、下列选项中，（ ）是引用类型。 A.enum类型 B.struct类型 C.string类型 D.int类型 2、下列描述错误的是（ ） A.类不可以多重继承而接口可以； B.抽象类自身可以定义成员而接口不可以： C.抽象类和接口都不能被实例化： D.一个类可以有多个基类和多个基接口： 3、下列关于C#中索引器理解正确的是（ ） A.索引器的参数必须是两个或两个以上 B.索引器的参数类型必须是整数型 C.索引器没有名字 D.以上皆非 4、下列关于构造函数的描述正确的是（ ） A.构造函数可以声明返回类型。 B.构造函数不可以用private修饰 C.构造函数必须与类名相同 D.构造函数不能带参数 5、接口是一种引用类型，在接口中可以声明（ ），但不可以声明公有的域或私有的成员变量 A.方法、属性、索引器和事件： B.方法、属性信息、属性； C.索引器和字段； D.事件和字段：二、填空题(每空2分，共20分)1、C#的数据类型有值类型和_________________。 2、面向对象是一种新兴的程序设计方法，面向对象的基本特征有_________________、_________________、_________________。 3、构造函数在_________________时被调用。 4、类是一种数据结构，它使用_________________关健字声明。 5、类声明后，可以创建类的实例，创建类的实例要使用_________________关键字。 6、一个接口定义一个协定。实现接口的类或结构必须遵守其协定。接口的声明格式为：_________________。 7、抽象类是一种不能直接创建对象的类，通常是部分实现的或者完全不实现。抽象类使用关键字_________________来声明。 8、创建新对象时将调用类的_________________。它主要用来为对象分配存储空间，完成初始化操作。三、编程题(共70分) 1、编写一个接口ITest,,包含两个方法GetArea()和GetZC(),分别用来求圆的面积和周长 定义一个类Circle来实现接口Test里面的方法，分别输出圆的面积和周长，并声明一个double数据类型的字段半径R,写一个有参的构造方法用来初始化半径R,（要求必须写无参构造方法） 在Program类里面初始化一个对象cir来分别调用求周长和面积的方法（30分） (接口10分，类的构造方法5分，继承5分，方法的实现10分，主入口测试5分） 2、创建Calculate基类，其中包含两个整型的protected成员，用以接收用户输入的两个整数。定义一个DisplayResult()虚方法，计算并显示结果 定义四个类(One、Two、Three、Four)派生自Calculate类，分别重写DisplayResult()虚方法，分别实现两个整数的加、减、乘、除运算并输出结果 实例化四个对象，分别调用四个类里面的方法实现加、减、乘、除(40分) (基类中protected成员4分，虚方法6分：派生类20分，每个5分：实例化四个对象并调用方法实现加减乘除10分）
第八章抽象类和接口目标{dotted startColor="#ff6c6c" endColor="#1989fa"/}抽象类和抽象方法用来列举一个类所需要的行为不明确提高具体实现方法必须有其子类实现它的抽象方法抽象方法·只指明方法的返回值类型、方法名称及参数，而不提供方法的实现。抽象类语法[访问修饰符]abstract class类名 { 代码 }抽象类案例 abstract class People//抽象类 { string name; string sex; public string Name { get => name; set => name = value; }//字段封装 public string Sex { get => sex; set => sex = value; }//字段封装 /*public virtual void Speak() { Console.WriteLine("大家好，我是一个人"); }*/ public abstract void Speak();//把Speak定义为抽象方法，使用关键字abstract }抽象类特性抽象类不能实例化抽象类可以包含抽象方法和抽象访问器不能用sealed修饰符修改抽象类，这意味着抽象类不能被继承从抽象类派生的非抽象类必须包括继承的所有抽象方法和抽象访问器的实现抽象类里面只有方法的声明，没有方法的主体抽象方法不能是静态的，不能用static抽象方法不能标记为virtual抽象类注意事项注意：(1)抽象方法只能在派生类中才能真正实现(2)一个类中只要有一个抽象方法，该类必须定义为抽象类(3)抽象方法只指明返回值类型、方法名称及参数(4)定义成抽象方法的目的在于指定派生类必须实现这一方法的功能(5)抽象类可以有构造方法，但是构造方法不能直接被调用而只能由派生类的构造方法调用虚方法和抽象方法虚方法抽象方法用virtual修饰用abstract修饰要有方法体，哪怕是一个分号不允许有方法体可以被子类override必须被子类override除了密封类都可以写只能在抽象类中{dotted startColor="#ff6c6c" endColor="#1989fa"/}接口全部是为实现的方法语法[属性][修饰符]interface 接口名 { //接口主体 }接口中只能声明方法、属性、索引器和事件接口不能声明字段、构造方法、常量和委托接口的成员默认是public的，如果明确指定成员的访问级别会报编译错误接口中所有的方法、属性和索引器都必须没有实现C#中的接口以大写字母“I”开头接口定义内容//定义接口，定义后不需要改变，需要不同功能，继承时扩展即可 interface IPrint { void Print(); //只定义，不实现 //IPerson(); //错误，未写返回值 //string name; //错误,定义字段 //public void GetlDcard(); //错误，指定访问级别 //void GetName(); //正确 //void GetAge(string s); //正确 //int GetHeight(); //正确 }使用接口类实现接口与继承一样，需要使用冒号运算符与抽象类不同的是，类是实现了接口中的方法而不是重写，所以实现接口的方法时不需要override关键字。//A继承接口 class A IPrint { //实现接口方法，必须有，//当然还可以再添加其它的字段、属性、方法 public void Print() { System.Console.WriteLine("A"); } } //B继承接口 class B:IPrint { public void Print() { System.Console.WriteLine("B"); } }using System.Collections.Generic; using System.Text; using System.Threading; namespace AppTest { class Demo interface { static void Main(string[]args) { //使用(注意，这里是使用接口IPirnt,下面是不同的实例，获得不同功能) IPrint I; I=new A();//实例化A,将打印出A I.Print(); I=new B();//实例化B,将打印出B I.Print(); Thread.Sleep(3*1000);//暂停3秒，看打印结果 } } }思考写的不错，不过这个例子还缺少一部分，人家可以说我可以在基类上定义Print(),PrintPreview()2个虚函数，让后续不同打机的类继承这个基类，override虚函数，然后通过基类指针一样可以实现这个功能。如果你这么说，如果要给HP打印机和IBM打印机增加一个新功能如Scan(),如果用基类虚函数就得重新修改基类，基类修改会影响到所有继承他的类，系统成型后修改基类是非常危险的，而用接口只需让HP的，IBM的打印类再继承一个Scan接口就行了，不会影响到其他类，这就是接口优越于虚函数的地方。{dotted startColor="#ff6c6c" endColor="#1989fa"/}接口作为方法的参数继承基类并实现接口一个类既可以派生自另一个类还可以同时实现某个接口一个类继承基类同时又实现接口时基类名要写在接口名的前面多重接口实现一个类可以同时实现多个接口实现多个接口只需要在定义类时在后面添加一个逗号和接口名类的代码中实现新接口的所有方法语法 static void Main(string[] args) { IPrint iHp = new PrintHP(); IPrint iIBM = new PrintIBM(); PrintPhoto(iHp); PrintPhoto(iIBM); } //打印照片的方法 public static void PrintPhoto(IPrint i)//接口作为参数 { i.Print(); }接口作为参数的意义实际上要接收的是一个实现这个接口的对象每个实现该接口的对象代码不一样，那么传递给方法执行时的结果也就不一样。通过接口也就实现了多态接口的绑定接口绑定就是把不同的接口合在一起一个新的接口 //用接口继承接口，就是接口的绑定 interface ISumSports:ISports,ILaLaDui { void KaiMuShi(); }{dotted startColor="#ff6c6c" endColor="#1989fa"/}is和as关键字is测试一个实例是不是另一个类型as同is同时把实例转换为另一种类型，如果转换不成功则返回null static void Main(string[] args) { //is关键字：判断一个实例是不是另一种数据类型，返回值为true或者false Sports s1 = new Sports(); if (s1 is ISports) { s1.KaiMuShi(); } else { s1.Sing(); } //as关键字，同is，把一种类型作为另一种类型使用，如果转换成功，返回目标数据类型，转换不成功，返回null; ISumSports isum = s1 as ISumSports; if (isum !=null) { isum.Dance(); } else { isum.QianQiu(); }抽象类与接口比较{dotted startColor="#ff6c6c" endColor="#1989fa"/}总结抽象方法没有代码实现的方法，使用abstract关键字修饰抽象类使用abstract关键字修饰是指包含0到多个抽象方法的类抽象类不能实例化含有抽象方法的类必须是抽象类重写抽象类的方法也用override关键字接口使用interface关键字修饰接口中只定义方法的原型，接口中不能有字段和常量继承接口的类必须实现接口中所有的方法才能实例化is和as关键字测试一个实例是不是另一个类型as同时把实例转换为另一种类型，如果转换不成功则返回null
继承的基本概念继承中的构造方法密封类多态重载（见第四章第四节）同一类中方法名相同参数不同重写子类中对父类的方法进行修改或者重新编写父类的对象可以指向子类的实例，并且调用子类重写重写的步骤在父类中把某个方法定义为虚方法，使用virtual关键字 class People { public virtual void Speak() { Console.WriteLine("大家好！我是一个人！"); } }在子类中使用override关键字重写父类的虚方法 class Student:People//继承 { public override void Speak() { Console.WriteLine("大家好，我是一名学生，我叫{0},性别{1},年龄{2}",name,sex,age); } }总结继承子类可以继承父类的非私有成员。不能继承父类的构造方法，子类构造方法会自动调用父类构造方法，并且父类构造方法先执行，再执行子类构造方法。使用 base关键字显示调用父类构造方法。base关键字还可以访问父类成员。protectedi访问修饰符修饰的成员可以被子类和本身访问，其他类访问不了。密封类sealed关键字修饰的类，表示不能被其他类继承。多态是指二个或多个不同的类，对同一方法的不同代码实现。virtual、override关键字，子类重写父类的虚方法。父类对象可以引用子类实例，并且调用子类重写的方法。