《C-程序设计项目教程》教学课件-项目十四_第1页
《C-程序设计项目教程》教学课件-项目十四_第2页
《C-程序设计项目教程》教学课件-项目十四_第3页
《C-程序设计项目教程》教学课件-项目十四_第4页
《C-程序设计项目教程》教学课件-项目十四_第5页
已阅读5页,还剩85页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

C#程序设计

工程教程计算机“十二五〞规划教材工程十四C#程序设计

工程教程计算机“十二五〞规划教材工程十四C#程序设计工程教程学习任务掌握泛型的概念以及泛型类和泛型方法的应用。

了解泛型约束的概念和使用方法。掌握泛型集合的应用。工程十四泛型——提高代码重用的最好方法C#程序设计工程教程学习任务工程十四泛型——提高代码重2C#程序设计工程教程任务安排任务一熟悉泛型根底知识任务二泛型约束任务三泛型集合类工程十四泛型——提高代码重用的最好方法C#程序设计工程教程任务安排工程十四泛型——提高代码重3C#程序设计工程教程任务一熟悉泛型根底知识任务说明预备知识在本任务中我们先来学习泛型的根底知识。一、为什么要使用泛型泛型用一个通过的数据类型T来代替object,在类实例化时指定T的类型,运行时〔Runtime〕自动编译为本地代码,运行效率和代码质量都有很大提高,并且保证数据类型平安。使用泛型来定义栈publicclassStack<T>{privateT[]m_item;publicTPop(){...}publicvoidPush(Titem){...}publicStack(inti){this.m_item=newT[i];}}C#程序设计工程教程任务一熟悉泛型根底知识任务说明预备知4C#程序设计工程教程在实例化时用一个实际的类型来代替数据类型T,如下所示:Stack<int>a=newStack<int>(100);//实例化只能保存int类型的类a.Push(10);//a.Push("8888"); //这一行编译不通过,因为类a只接收int类型的数据intx=a.Pop();Stack<string>b=newStack<string>(100);//实例化只能保存string类型的类//b.Push(10); //这一行编译不通过,因为类b只接收string类型的数据b.Push("8888");stringy=b.Pop();泛型类有如下优点:①类型平安②无需装箱和折箱③无需类型转换C#程序设计工程教程在实例化时用一个实际的类型来代替数据类型5C#程序设计工程教程二、泛型类与泛型方法〔一〕泛型类声明泛型类的语法格式如下:类修饰符Class类名<T>:基类/接口{//相关代码}泛型类可以在其定义中包含多个泛型类型,用逗号分隔开,例如:PublicClassMyGenericClass<T1,T2,T3>{//……}定义这些类型之后,可以将它们用作成员变量的类型、属性或方法成员的返回类型等。另外,在泛型类中也可以使用普通数据类型,可以包含非泛型方法。C#程序设计工程教程二、泛型类与泛型方法〔一〕泛型类声明泛型6C#程序设计工程教程C#在编译泛型类时,先生成中间代码〔IL〕,通用类型T只是一个占位符。在实例化类时,根据用户指定的数据类型代替T并由即时编译器〔JIT〕生本钱地代码,这个本地代码中已经使用了实际的数据类型,等同于用实际类型写的类,所以不同的封闭类〔这里封闭类是指由相同数据类型参数实例化的类〕的本地代码是不一样的。例如:Stack<int>和Stack<string>是两个完全没有任何关系的封闭类,你可以将它们看成类A和类B。C#程序设计工程教程C#在编译泛型类时,先生成中间7C#程序设计工程教程〔二〕泛型方法除了方法之外,其他的类成员如字段、属性和方法等不能有自定义的泛型类型。声明泛型方法的格式如下:修饰符返回类型方法名<泛型类型形参表>(形参表);{//其它语句}下面我们来看一段应用泛型方法的代码:publicclassStack2{publicvoidPush<T>(Stack<T>s,paramsT[]p){foreach(Ttinp){s.Push(t);}}}C#程序设计工程教程〔二〕泛型方法除了方法之外,其他8C#程序设计工程教程Stack2类可以一次将多个数据压入Stack中。其中Push是一个泛型方法,调用这个方法的例如如下:Stack<int>x=newStack<int>(100);Stack2x2=newStack2();x2.Push(x,1,2,3,4,6);strings="";for(inti=0;i<5;i++){s+=x.Pop().ToString();} //至此,s的值为64321C#程序设计工程教程Stack2类可以一次将多个数据9C#程序设计工程教程〔三〕泛型中的静态成员变量在泛型类中,静态成员变量在相同封闭类间共享,不同的封闭类间不共享。例如:Stack<int>a=newStack<int>();Stack<int>b=newStack<int>();Stack<long>c=newStack<long>();类实例a和b是同一类型,他们之间共享静态成员变量;但类实例c却和a、b是完全不同的类型,所以不能和a、b共享静态成员变量。C#程序设计工程教程〔三〕泛型中的静态成员变量在泛型10C#程序设计工程教程〔四〕泛型类中的静态构造函数静态构造函数只能有一个,且不能有参数,且只能在.NET运行时自动被调用,不能人工调用。我们把泛型中的不同的封闭类理解为不同的类,那么泛型中的静态构造函数的原理和非泛型类是一样的。静态的构造函数只在以下两种情况被激发:①特定的封闭类第一次被实例化。②特定封闭类中任一静态成员变量被调用。C#程序设计工程教程〔四〕泛型类中的静态构造函数静态构11C#程序设计工程教程〔五〕泛型类中的方法重载通过一个例子来进行学习:publicclassNode<T,V>{

publicTadd(Ta,Vb)//第一个add

{

returna;

}

publicTadd(Va,Tb)//第二个add

{

returnb;

}

publicintadd(inta,intb)//第三个add

{

returna+b;

}}当使用下面的调用代码时Node<string,int>node=newNode<string,int>();objectx=node.add(2,"11");这两行调用代码可正确编译,因为传入的string和int,使三个add方法具有不同的签名,当然能找到唯一匹配的add方法。但如果T和V都传入int类型,三个add方法将具有同样的签名,请看下面代码:Node<int,int>node=newNode<int,int>();objectx=node.add(2,11);此时,这个类仍然能通过编译,且能调用成功。因为系统会优先匹配了第三个add方法。如果删除了第三个add,上面的调用代码那么无法编译通过,提示方法产生混淆无法在第一个add和第二个add之间选择。C#的泛型是在实例的方法被调用时检查重载是否产生混淆,而不是在泛型类本身编译时检查;当一般方法与泛型方法具有相同的签名时,会覆盖泛型方法。C#程序设计工程教程〔五〕泛型类中的方法重载通过一个例子来进12C#程序设计工程教程任务实施——利用泛型类显示信息任务说明本案例主要完成的是通过下拉列表的ValueMember字段隐藏一些数据。数据类型只有在运行时才知道,即可能是根本数据类型,也可能是类类型,需要用泛型类实现这个功能。实施步骤步骤1 创立一个Windows窗体应用程序,将其命名为MySchool。向Form1窗体中添加一个Button控件,修改其Text值为“泛型类〞。然后向该工程中添加一个窗体,将其命名为FrmGenericClass,修改其Text值为“泛型类〞,并在此窗体中添加2个Label控件和2个ComboBox控件,并设置label1、label2的Text值分别为“学生集合〞、“教师集合〞。修改Form1窗体中Button控件的name值为“btnGenericClass〞,双击该按钮添加其click事件代码,如下所示:privatevoidbtnGenericClass_Click(objectsender,EventArgse) //调用泛型类窗体{

FrmGenericClassfrm=newFrmGenericClass();frm.Show();}C#程序设计工程教程任务实施——利用泛型类显示信息任务说明13C#程序设计工程教程步骤2 在应用程序下添加Student类,完整代码如下:namespaceMySchool{publicclassStudent{publicStudent():this("张三",20){}publicStudent(stringname,intage){this.Name=name;this.Age=age;}privatestringname;publicstringName{get{returnname;}set{name=value;}}privateintage;publicintAge{get{returnage;}set{if(value>0&&value<100){age=value;}else{age=18;}}}publicvoidSayHi()(“大家好,我是{0}同学,今年{1}岁了“,,this.age);MessageBox.Show(message);}}}C#程序设计工程教程步骤2 在应用程序下添加Studen14C#程序设计工程教程步骤3 在应用程序下添加Teacher类,完整代码如下:namespaceMySchool{publicclassTeacher{publicTeacher(stringname):this(name,2,5000){}publicTeacher(stringname,intservingYears):this(name,servingYears,5000){}publicTeacher(stringname,intservingYears,intsalary){=name;this.servingYears=servingYears;this.salary=salary;}privatestringname;publicstringName{get{returnname;}set{name=value;}}C#程序设计工程教程步骤3 在应用程序下添加Teache15C#程序设计工程教程privateintsalary;publicintSalary{get{returnsalary;}set{salary=value;}}privateintservingYears;publicintServingYears{get{returnservingYears;}set{servingYears=value;}}publicvoidSayHi(){stringmessage=string.Format("大家好,我是{0}老师。我已经在教育战线奋斗了{1}年了!",,this.servingYears);MessageBox.Show(message);}}}C#程序设计工程教程privateintsala16C#程序设计工程教程步骤4 该工程中添加一个类文件,为其添加泛型类ComboBoxItem,详细代码如下所示:namespaceMySchool{//定义泛型类publicclassComboBoxItem<T>{privatestringitemText;publicstringItemText{get{returnitemText;}set{itemText=value;}}privateTitemValue;publicTItemValue{get{returnitemValue;}set{itemValue=value;}}}}C#程序设计工程教程步骤4 该工程中添加一个类文件,为其17C#程序设计工程教程步骤5 在FrmGenericClass窗体的Load事件中添加代码如下:privatevoidFrmGenericClass_Load(objectsender,EventArgse){Studentzhang=newStudent("张三",20);Studentli=newStudent("李四",19);Studentwang=newStudent("王五",20);Teachernie=newTeacher("聂树成",4);Teachertian=newTeacher("田天",2);//创立Combox项,运行时确定泛型类支持的数据类型ComboBoxItem<Student>itemzhang=newComboBoxItem<Student>();itemzhang.ItemText=zhang.Name;itemzhang.ItemValue=zhang;ComboBoxItem<Student>itemli=newComboBoxItem<Student>();itemli.ItemText=li.Name;itemli.ItemValue=li;ComboBoxItem<Student>itemwang=newComboBoxItem<Student>();itemwang.ItemText=wang.Name;itemwang.ItemValue=wang;C#程序设计工程教程步骤5 在FrmGenericCla18C#程序设计工程教程//创立支持学生类型的Items集合List<ComboBoxItem<Student>>items=newList<ComboBoxItem<Student>>();items.Add(itemzhang);items.Add(itemli);items.Add(itemwang);//在cboStudents下拉列表框显示学生cboStudents.DataSource=items;cboStudents.DisplayMember="ItemText";cboStudents.ValueMember="ItemValue";//创立支持教师类型的Combox项ComboBoxItem<Teacher>itemtian=newComboBoxItem<Teacher>();itemtian.ItemText=tian.Name;itemtian.ItemValue=tian;ComboBoxItem<Teacher>itemnie=newComboBoxItem<Teacher>();itemnie.ItemText=nie.Name;itemnie.ItemValue=nie;//创立Items集合,支持教师类型List<ComboBoxItem<Teacher>>itemsT=newList<ComboBoxItem<Teacher>>();itemsT.Add(itemtian);itemsT.Add(itemnie);C#程序设计工程教程//创立支持学生类型的Items集合19C#程序设计工程教程//在cboTeachers下拉列表框显示教师this.cboTeachers.DataSource=itemsT;cboTeachers.DisplayMember="ItemText";cboTeachers.ValueMember="ItemValue";}privatevoidcboStudents_SelectedIndexChanged(objectsender,EventArgse){if(cboStudents.SelectedIndex>0){Studentstu=(Student)cboStudents.SelectedValue;stu.SayHi();}}privatevoidcboTeachers_SelectedIndexChanged(objectsender,EventArgse){if(cboTeachers.SelectedIndex>0){TeacherTea=(Teacher)cboTeachers.SelectedValue;Tea.SayHi();}}C#程序设计工程教程//在cboTeachers下拉列表框显20C#程序设计工程教程步骤6 按【Ctrl+F5】键程序运行,在弹出的对话框中单击“泛型类〞按钮,将弹出“泛型类〞对话框,在此对话框中选择不同的值,系统将弹出不同的信息提示,如以下图所示。C#程序设计工程教程步骤6 按【Ctrl+F5】键程序运21C#程序设计工程教程任务二

泛型约束任务说明在定义泛型类时,我们可以对用户实例化类时所使用的类型参数的种类施加限制,如果用户尝试使用某个约束所不允许的类型来实例化类,那么会产生编译错误。在C#中这些限制就称为约束,本节我们就来学习与此相关的知识。预备知识约束的方式是指定T的祖先,即继承的接口或类。因为C#的单根继承性,所以约束可以有多个接口,但最多只能有一个类,并且类必须在接口之前。定义约束需要使用关键字where,如下所示:publicclassNode<T,V>whereT:Stack,IComparablewhereV:Stack{//...}T必须是从Stack和IComparable继承的类型,V必须是Stack类型或从Stack继承的类型,否那么将无法通过编译器的类型检查。C#程序设计工程教程任务二泛型约束任务说明在定义泛22C#程序设计工程教程下面我们来看几种常见的约束:〔1〕结构约束结构约束的格式如下:T〔类型〕:struct表示类型参数必须是值类型。〔2〕类约束T〔类型〕:class表示类型参数必须是引用类型,包括任何类、接口、委托或数组类型。publicstructA{}publicclassB{}classC<T>whereT:struct{//T是一个值类型}C<A>c=newC<A>();//正确,A是一个值类型C<B>c=newC<B>();//错误,B是一个引用类型C#程序设计工程教程下面我们来看几种常见的约束:〔1〕结构约23C#程序设计工程教程〔3〕新建约束T〔类型〕:new()表示类型参数必须具有无参数的公共构造方法。当与其他约束一起使用时,new()约束必须最后指定。例如:classA{publicvoidA(){}}classB{publicvoidB(inti){}}classC<T>whereT:new(){Tt=newT();}C<A>c=newC<A>();//正确,A有无参构造方法C<B>c=newC<B>();//错误,B没有无参构造方法C#程序设计工程教程〔3〕新建约束T〔类型〕:new()24C#程序设计工程教程〔4〕基类约束T〔类型〕:<基类名>用来限制参数类型从特定的类中派生,例如:classA{publicvoidF1(){}}classB{publicvoidF2(){}}classC<S,T>whereS:AwhereT:B{//可以在类型为S的变量上调用F1//可以在类型为T的变量上调用F2}C#程序设计工程教程〔4〕基类约束T〔类型〕:<基类名>用来25C#程序设计工程教程〔5〕接口约束T〔类型〕:<接口名>表示类型参数必须是指定的接口或实现指定的接口。可以指定多个接口约束。约束接口也可以是泛型的。例如:interfaceIPrintable{voidPrint();}interfaceIComparable<T>{intComparableTo(Tv);}interfaceIKeyProvider<T>{TGetKey();}classDictionary<K,V>whereK:IComparable<K>whereV:IPrintable,IKeyProvider<K>{//可以在类型为K的变量上调用CompareTo//可以在类型为V的变量上调用Print和GetKey}C#程序设计工程教程〔5〕接口约束T〔类型〕:<接口名>26C#程序设计工程教程〔6〕裸类约束〔nakedtypeconstraint〕T〔类型〕:U(被约束对象)表示为T提供的类型参数必须是为U提供的参数,或者是派生自为U提供的参数。例如:ClassMyGenericClass<T1,T2>whereT2:T1{//…}其中,T2必须与T1的类型相同,或者继承自T1。C#程序设计工程教程〔6〕裸类约束〔nakedtypec27C#程序设计工程教程任务实施——泛型约束应用任务说明在本任务中创立Animal、Cow和Chicken等动物类,然后通过泛型类Farm来访问其他类的方法,Farm类被约束为Anima1类型。实施步骤步骤1 新建一Windows窗体应用程序,命名为“MyAnimal〞。向窗体中添加一个Button控件,设置其Text值为“泛型类型约束〞。步骤2 在应用程序下添加抽象Animal类,完整代码如下:namespaceMyAnimal{publicabstractclassAnimal{publicAnimal(){}publicAnimal(stringnewName){name=newName;}protectedstringname;C#程序设计工程教程任务实施——泛型约束应用任务说明在28C#程序设计工程教程publicstringName{get{returnname;}set{name=value;}}//喂饲料publicvoidFeed(){MessageBox.Show("已经有饲料了",name);}//动物发出叫声publicabstractvoidMakeANoise();}}C#程序设计工程教程publicstringName29C#程序设计工程教程步骤3 在应用程序下添加Chicken类,继承于Animal类,完整代码如下:publicclassChicken:Animal{publicChicken(stringnewName):base(newName){}publicvoidLayEgg(){MessageBox.Show("下了一个蛋",name);}publicoverridevoidMakeANoise(){MessageBox.Show("嘎!嘎!嘎嘎",name);}}C#程序设计工程教程步骤3 在应用程序下添加Chicke30C#程序设计工程教程步骤4 在应用程序下添加Cow类,继承于Animal类,完整代码如下:publicclassCow:Animal{publicCow(stringnewName):base(newName){}publicvoidMilk(){MessageBox.Show("产一桶奶",name);}publicoverridevoidMakeANoise(){MessageBox.Show("哞!哞!哞!",name);}}C#程序设计工程教程步骤4 在应用程序下添加Cow类,继31C#程序设计工程教程步骤5 在应用程序下添加SuperCow类,继承于Cow类,完整代码如下:publicclassSuperCow:Cow{publicSuperCow(stringnewName):base(newName){}publicvoidFly(){MessageBox.Show("飞翔",name);}publicoverridevoidMakeANoise(){MessageBox.Show("我是奶牛超人",name);}}C#程序设计工程教程步骤5 在应用程序下添加SuperC32C#程序设计工程教程步骤6 在应用程序下添加Farm类,定义为泛型类并约束Animal类,代码如下:publicclassFarm<T>whereT:Animal{privateList<T>animals=newList<T>(); //List<T>的相关知识详见任务三publicList<T>Animals{get{returnanimals;}}publicIEnumerator<T>GetEnumerator(){returnanimals.GetEnumerator();}publicvoidMakeNoises(){foreach(Tanimalinanimals){animal.MakeANoise();}}C#程序设计工程教程步骤6 在应用程序下添加Farm类,33C#程序设计工程教程publicvoidFeedTheAnimals(){foreach(Tanimalinanimals){animal.Feed();}}publicFarm<Cow>GetCows(){Farm<Cow>cowFarm=newFarm<Cow>();foreach(Tanimalinanimals){if(animalisCow){cowFarm.Animals.Add(animalasCow);}}returncowFarm;}}C#程序设计工程教程publicvoidFeedTheA34C#程序设计工程教程步骤7 双击按钮,在其Click事件中添加如下代码:privatevoidbutton1_Click(objectsender,EventArgse){Farm<Animal>farm=newFarm<Animal>();farm.Animals.Add(newCow("Jack牛"));farm.Animals.Add(newChicken("Vera鸡"));farm.Animals.Add(newChicken("Sally鸡"));farm.Animals.Add(newSuperCow("Kevin超人牛"));farm.MakeNoises();Farm<Cow>dairyFarm=farm.GetCows();dairyFarm.FeedTheAnimals();foreach(CowcowindairyFarm){if(cowisSuperCow){(cowasSuperCow).Fly();}}}步骤8 按【Ctrl+F5】键运行程序,查看运行结果。C#程序设计工程教程步骤7 双击按钮,在其Click事件35C#程序设计工程教程任务三

泛型集合类任务说明泛型的一个重要应用就是泛型集合。在工程十中我们学习集合时提到过泛型集合类,它位于命名空间中。本节我们就来学习有关泛型集合类的知识。预备知识下表以对照的方式列举了最为常用的泛型集合类和同功能的非泛型集合。C#程序设计工程教程任务三泛型集合类任务说明泛型的36C#程序设计工程教程一、List<T>泛型集合类List<T>类的用法非常类似于ArrayList,两者的异同如下表所示。C#程序设计工程教程一、List<T>泛型集合类List<T37C#程序设计工程教程定义List<T>语法:List<T>对象名=newList<T>();List<T>中相关方法和属性的说明如下表所示。C#程序设计工程教程定义List<T>语法:List<T>38C#程序设计工程教程二、Dictionary<TKey,TValue>泛型集合类泛型集合Dictionary<TKey,TValue>,具有泛型的全部特性。编译时检查类型约束,获取元素时无须类型转换,并且它存储数据的方式和哈希表类似,也是通过Key/Value〔键/值〕保存元素的。定义Dictionary<TKey,TValue>泛型集合的格式如下:Dictionary<K,V>对象名=newDictionary<K,V>();<K,V>中的K表示集合中Key的类型,V表示Value的类型。C#程序设计工程教程二、Dictionary<TKey,TV39C#程序设计工程教程任务实施1——List<T>泛型集合应用任务说明本案例利用泛型集合List<T>的知识输出学生相关信息,案例效果是单击“泛型集合List<T>〞按钮,将顺序显示学生的相关信息,如以下图所示。C#程序设计工程教程任务实施1——List<T>泛型集合应用40C#程序设计工程教程实施步骤步骤1 翻开任务一中的“MySchool〞Windows应用程序,向窗体Form1中添加一个Button按钮,将其Text值设为为“泛型集合List<T>〞,name值为“btnList〞。再添加一个按钮,将其Text值修改为“删除泛型集合〞,name值为“btnDelete〞。在类Form1中创立几个对象,代码如下:List<Student>students; //泛型集合类List<T>对象Studentzhang; //学生对象Studentli; //学生对象Studentwang; //学生对象步骤2 双击“泛型集合List<T>〞按钮,在其单击事件中添加如下代码:privatevoidbtnList_Click(objectsender,EventArgse){students=newList<Student>();Studentzhang=newStudent("张三",20);Studentli=newStudent("李四",19);Studentwang=newStudent("王五",20);C#程序设计工程教程实施步骤步骤1 翻开任务一中的“My41C#程序设计工程教程Teachernie=newTeacher("聂树成",4);

students.Add(zhang);students.Add(li);students.Add(wang);//打印集合数目

MessageBox.Show(string.Format(“班级共包括{0}个成员。",students.Count.ToString()));foreach(Studentstuinstudents){stu.SayHi();}}privatevoidbtnDelete_Click(objectsender,EventArgse){Studentstu=students[0];//通过索引访问stu.SayHi();students.RemoveAt(0);//通过索引或者对象删除students.Remove(li);foreach(Studentsuinstudents){su.SayHi();}}步骤3 双击“删除泛型集合〞按钮,在其单击事件中添加如下代码:步骤4 按【Ctrl+F5】键运行程序。C#程序设计工程教程Teachernie=newTe42C#程序设计工程教程任务实施2——Dictionary<TKey,TValue>泛型集合应用任务说明本案例利用泛型集合Dictionary的知识输出学生相关信息,案例实现的最终效果是单击“泛型集合Dictionary<TKey,TValue>〞按钮,将顺序显示学生的相关信息。程序运行结果如以下图所示。C#程序设计工程教程任务实施2——Dictionary<TK43C#程序设计工程教程实施步骤步骤1 翻开“任务实施1〞中的MySchool应用程序,向窗体Form1中添加一个Button按钮,并将其Text值修改为“泛型集合Dictionary<TKey,TValue>〞,name值修改为“btnList〞。双击该按钮,为其单击事件添加如下代码:privatevoidbtnDictionary_Click(objectsender,EventArgse){//定义一个Dictionary泛型集合stusDictionary<String,Student>stus=newDictionary<string,Student>();Studentzhang=newStudent("张三",20);Studentli=newStudent("李四",19);Studentwang=newStudent("王五",20);Teachernie=newTeacher("聂树成",4);#region添加元素演示stus.Add(zhang.Name,zhang);stus.Add(li.Name,li);stus.Add(wang.Name,wang);//stus.Add(nie.Name,nie); //假设添加教师信息,编译时立即报错C#程序设计工程教程实施步骤步骤1 翻开“任务实施1〞中44C#程序设计工程教程//打印集合数目MessageBox.Show(string.Format("共包括{0}个学员。",stus.Count.ToString()));#endregion#region存取单个元素演示Studentstu2=stus["张三"];stu2.SayHi();#endregion#region元素遍历演示foreach(Studentstudentinstus.Values){student.SayHi();}#endregion#region删除元素演示//打印集合数目MessageBox.Show(string.Format("共包括{0}个学员。",stus.Count.ToString()));stus.Remove("张三");//打印集合数目MessageBox.Show(string.Format("共包括{0}个学员。",stus.Count.ToString()));#endregion}步骤2 按【Ctrl+F5】键运行程序。C#程序设计工程教程//打印集合数目步骤2 按【Ctrl45C#程序设计

工程教程计算机“十二五〞规划教材工程十四C#程序设计

工程教程计算机“十二五〞规划教材工程十四C#程序设计工程教程学习任务掌握泛型的概念以及泛型类和泛型方法的应用。

了解泛型约束的概念和使用方法。掌握泛型集合的应用。工程十四泛型——提高代码重用的最好方法C#程序设计工程教程学习任务工程十四泛型——提高代码重47C#程序设计工程教程任务安排任务一熟悉泛型根底知识任务二泛型约束任务三泛型集合类工程十四泛型——提高代码重用的最好方法C#程序设计工程教程任务安排工程十四泛型——提高代码重48C#程序设计工程教程任务一熟悉泛型根底知识任务说明预备知识在本任务中我们先来学习泛型的根底知识。一、为什么要使用泛型泛型用一个通过的数据类型T来代替object,在类实例化时指定T的类型,运行时〔Runtime〕自动编译为本地代码,运行效率和代码质量都有很大提高,并且保证数据类型平安。使用泛型来定义栈publicclassStack<T>{privateT[]m_item;publicTPop(){...}publicvoidPush(Titem){...}publicStack(inti){this.m_item=newT[i];}}C#程序设计工程教程任务一熟悉泛型根底知识任务说明预备知49C#程序设计工程教程在实例化时用一个实际的类型来代替数据类型T,如下所示:Stack<int>a=newStack<int>(100);//实例化只能保存int类型的类a.Push(10);//a.Push("8888"); //这一行编译不通过,因为类a只接收int类型的数据intx=a.Pop();Stack<string>b=newStack<string>(100);//实例化只能保存string类型的类//b.Push(10); //这一行编译不通过,因为类b只接收string类型的数据b.Push("8888");stringy=b.Pop();泛型类有如下优点:①类型平安②无需装箱和折箱③无需类型转换C#程序设计工程教程在实例化时用一个实际的类型来代替数据类型50C#程序设计工程教程二、泛型类与泛型方法〔一〕泛型类声明泛型类的语法格式如下:类修饰符Class类名<T>:基类/接口{//相关代码}泛型类可以在其定义中包含多个泛型类型,用逗号分隔开,例如:PublicClassMyGenericClass<T1,T2,T3>{//……}定义这些类型之后,可以将它们用作成员变量的类型、属性或方法成员的返回类型等。另外,在泛型类中也可以使用普通数据类型,可以包含非泛型方法。C#程序设计工程教程二、泛型类与泛型方法〔一〕泛型类声明泛型51C#程序设计工程教程C#在编译泛型类时,先生成中间代码〔IL〕,通用类型T只是一个占位符。在实例化类时,根据用户指定的数据类型代替T并由即时编译器〔JIT〕生本钱地代码,这个本地代码中已经使用了实际的数据类型,等同于用实际类型写的类,所以不同的封闭类〔这里封闭类是指由相同数据类型参数实例化的类〕的本地代码是不一样的。例如:Stack<int>和Stack<string>是两个完全没有任何关系的封闭类,你可以将它们看成类A和类B。C#程序设计工程教程C#在编译泛型类时,先生成中间52C#程序设计工程教程〔二〕泛型方法除了方法之外,其他的类成员如字段、属性和方法等不能有自定义的泛型类型。声明泛型方法的格式如下:修饰符返回类型方法名<泛型类型形参表>(形参表);{//其它语句}下面我们来看一段应用泛型方法的代码:publicclassStack2{publicvoidPush<T>(Stack<T>s,paramsT[]p){foreach(Ttinp){s.Push(t);}}}C#程序设计工程教程〔二〕泛型方法除了方法之外,其他53C#程序设计工程教程Stack2类可以一次将多个数据压入Stack中。其中Push是一个泛型方法,调用这个方法的例如如下:Stack<int>x=newStack<int>(100);Stack2x2=newStack2();x2.Push(x,1,2,3,4,6);strings="";for(inti=0;i<5;i++){s+=x.Pop().ToString();} //至此,s的值为64321C#程序设计工程教程Stack2类可以一次将多个数据54C#程序设计工程教程〔三〕泛型中的静态成员变量在泛型类中,静态成员变量在相同封闭类间共享,不同的封闭类间不共享。例如:Stack<int>a=newStack<int>();Stack<int>b=newStack<int>();Stack<long>c=newStack<long>();类实例a和b是同一类型,他们之间共享静态成员变量;但类实例c却和a、b是完全不同的类型,所以不能和a、b共享静态成员变量。C#程序设计工程教程〔三〕泛型中的静态成员变量在泛型55C#程序设计工程教程〔四〕泛型类中的静态构造函数静态构造函数只能有一个,且不能有参数,且只能在.NET运行时自动被调用,不能人工调用。我们把泛型中的不同的封闭类理解为不同的类,那么泛型中的静态构造函数的原理和非泛型类是一样的。静态的构造函数只在以下两种情况被激发:①特定的封闭类第一次被实例化。②特定封闭类中任一静态成员变量被调用。C#程序设计工程教程〔四〕泛型类中的静态构造函数静态构56C#程序设计工程教程〔五〕泛型类中的方法重载通过一个例子来进行学习:publicclassNode<T,V>{

publicTadd(Ta,Vb)//第一个add

{

returna;

}

publicTadd(Va,Tb)//第二个add

{

returnb;

}

publicintadd(inta,intb)//第三个add

{

returna+b;

}}当使用下面的调用代码时Node<string,int>node=newNode<string,int>();objectx=node.add(2,"11");这两行调用代码可正确编译,因为传入的string和int,使三个add方法具有不同的签名,当然能找到唯一匹配的add方法。但如果T和V都传入int类型,三个add方法将具有同样的签名,请看下面代码:Node<int,int>node=newNode<int,int>();objectx=node.add(2,11);此时,这个类仍然能通过编译,且能调用成功。因为系统会优先匹配了第三个add方法。如果删除了第三个add,上面的调用代码那么无法编译通过,提示方法产生混淆无法在第一个add和第二个add之间选择。C#的泛型是在实例的方法被调用时检查重载是否产生混淆,而不是在泛型类本身编译时检查;当一般方法与泛型方法具有相同的签名时,会覆盖泛型方法。C#程序设计工程教程〔五〕泛型类中的方法重载通过一个例子来进57C#程序设计工程教程任务实施——利用泛型类显示信息任务说明本案例主要完成的是通过下拉列表的ValueMember字段隐藏一些数据。数据类型只有在运行时才知道,即可能是根本数据类型,也可能是类类型,需要用泛型类实现这个功能。实施步骤步骤1 创立一个Windows窗体应用程序,将其命名为MySchool。向Form1窗体中添加一个Button控件,修改其Text值为“泛型类〞。然后向该工程中添加一个窗体,将其命名为FrmGenericClass,修改其Text值为“泛型类〞,并在此窗体中添加2个Label控件和2个ComboBox控件,并设置label1、label2的Text值分别为“学生集合〞、“教师集合〞。修改Form1窗体中Button控件的name值为“btnGenericClass〞,双击该按钮添加其click事件代码,如下所示:privatevoidbtnGenericClass_Click(objectsender,EventArgse) //调用泛型类窗体{

FrmGenericClassfrm=newFrmGenericClass();frm.Show();}C#程序设计工程教程任务实施——利用泛型类显示信息任务说明58C#程序设计工程教程步骤2 在应用程序下添加Student类,完整代码如下:namespaceMySchool{publicclassStudent{publicStudent():this("张三",20){}publicStudent(stringname,intage){this.Name=name;this.Age=age;}privatestringname;publicstringName{get{returnname;}set{name=value;}}privateintage;publicintAge{get{returnage;}set{if(value>0&&value<100){age=value;}else{age=18;}}}publicvoidSayHi()(“大家好,我是{0}同学,今年{1}岁了“,,this.age);MessageBox.Show(message);}}}C#程序设计工程教程步骤2 在应用程序下添加Studen59C#程序设计工程教程步骤3 在应用程序下添加Teacher类,完整代码如下:namespaceMySchool{publicclassTeacher{publicTeacher(stringname):this(name,2,5000){}publicTeacher(stringname,intservingYears):this(name,servingYears,5000){}publicTeacher(stringname,intservingYears,intsalary){=name;this.servingYears=servingYears;this.salary=salary;}privatestringname;publicstringName{get{returnname;}set{name=value;}}C#程序设计工程教程步骤3 在应用程序下添加Teache60C#程序设计工程教程privateintsalary;publicintSalary{get{returnsalary;}set{salary=value;}}privateintservingYears;publicintServingYears{get{returnservingYears;}set{servingYears=value;}}publicvoidSayHi(){stringmessage=string.Format("大家好,我是{0}老师。我已经在教育战线奋斗了{1}年了!",,this.servingYears);MessageBox.Show(message);}}}C#程序设计工程教程privateintsala61C#程序设计工程教程步骤4 该工程中添加一个类文件,为其添加泛型类ComboBoxItem,详细代码如下所示:namespaceMySchool{//定义泛型类publicclassComboBoxItem<T>{privatestringitemText;publicstringItemText{get{returnitemText;}set{itemText=value;}}privateTitemValue;publicTItemValue{get{returnitemValue;}set{itemValue=value;}}}}C#程序设计工程教程步骤4 该工程中添加一个类文件,为其62C#程序设计工程教程步骤5 在FrmGenericClass窗体的Load事件中添加代码如下:privatevoidFrmGenericClass_Load(objectsender,EventArgse){Studentzhang=newStudent("张三",20);Studentli=newStudent("李四",19);Studentwang=newStudent("王五",20);Teachernie=newTeacher("聂树成",4);Teachertian=newTeacher("田天",2);//创立Combox项,运行时确定泛型类支持的数据类型ComboBoxItem<Student>itemzhang=newComboBoxItem<Student>();itemzhang.ItemText=zhang.Name;itemzhang.ItemValue=zhang;ComboBoxItem<Student>itemli=newComboBoxItem<Student>();itemli.ItemText=li.Name;itemli.ItemValue=li;ComboBoxItem<Student>itemwang=newComboBoxItem<Student>();itemwang.ItemText=wang.Name;itemwang.ItemValue=wang;C#程序设计工程教程步骤5 在FrmGenericCla63C#程序设计工程教程//创立支持学生类型的Items集合List<ComboBoxItem<Student>>items=newList<ComboBoxItem<Student>>();items.Add(itemzhang);items.Add(itemli);items.Add(itemwang);//在cboStudents下拉列表框显示学生cboStudents.DataSource=items;cboStudents.DisplayMember="ItemText";cboStudents.ValueMember="ItemValue";//创立支持教师类型的Combox项ComboBoxItem<Teacher>itemtian=newComboBoxItem<Teacher>();itemtian.ItemText=tian.Name;itemtian.ItemValue=tian;ComboBoxItem<Teacher>itemnie=newComboBoxItem<Teacher>();itemnie.ItemText=nie.Name;itemnie.ItemValue=nie;//创立Items集合,支持教师类型List<ComboBoxItem<Teacher>>itemsT=newList<ComboBoxItem<Teacher>>();itemsT.Add(itemtian);itemsT.Add(itemnie);C#程序设计工程教程//创立支持学生类型的Items集合64C#程序设计工程教程//在cboTeachers下拉列表框显示教师this.cboTeachers.DataSource=itemsT;cboTeachers.DisplayMember="ItemText";cboTeachers.ValueMember="ItemValue";}privatevoidcboStudents_SelectedIndexChanged(objectsender,EventArgse){if(cboStudents.SelectedIndex>0){Studentstu=(Student)cboStudents.SelectedValue;stu.SayHi();}}privatevoidcboTeachers_SelectedIndexChanged(objectsender,EventArgse){if(cboTeachers.SelectedIndex>0){TeacherTea=(Teacher)cboTeachers.SelectedValue;Tea.SayHi();}}C#程序设计工程教程//在cboTeachers下拉列表框显65C#程序设计工程教程步骤6 按【Ctrl+F5】键程序运行,在弹出的对话框中单击“泛型类〞按钮,将弹出“泛型类〞对话框,在此对话框中选择不同的值,系统将弹出不同的信息提示,如以下图所示。C#程序设计工程教程步骤6 按【Ctrl+F5】键程序运66C#程序设计工程教程任务二

泛型约束任务说明在定义泛型类时,我们可以对用户实例化类时所使用的类型参数的种类施加限制,如果用户尝试使用某个约束所不允许的类型来实例化类,那么会产生编译错误。在C#中这些限制就称为约束,本节我们就来学习与此相关的知识。预备知识约束的方式是指定T的祖先,即继承的接口或类。因为C#的单根继承性,所以约束可以有多个接口,但最多只能有一个类,并且类必须在接口之前。定义约束需要使用关键字where,如下所示:publicclassNode<T,V>whereT:Stack,IComparablewhereV:Stack{//...}T必须是从Stack和IComparable继承的类型,V必须是Stack类型或从Stack继承的类型,否那么将无法通过编译器的类型检查。C#程序设计工程教程任务二泛型约束任务说明在定义泛67C#程序设计工程教程下面我们来看几种常见的约束:〔1〕结构约束结构约束的格式如下:T〔类型〕:struct表示类型参数必须是值类型。〔2〕类约束T〔类型〕:class表示类型参数必须是引用类型,包括任何类、接口、委托或数组类型。publicstructA{}publicclassB{}classC<T>whereT:struct{//T是一个值类型}C<A>c=newC<A>();//正确,A是一个值类型C<B>c=newC<B>();//错误,B是一个引用类型C#程序设计工程教程下面我们来看几种常见的约束:〔1〕结构约68C#程序设计工程教程〔3〕新建约束T〔类型〕:new()表示类型参数必须具有无参数的公共构造方法。当与其他约束一起使用时,new()约束必须最后指定。例如:classA{publicvoidA(){}}classB{publicvoidB(inti){}}classC<T>whereT:new(){Tt=newT();}C<A>c=newC<A>();//正确,A有无参构造方法C<B>c=newC<B>();//错误,B没有无参构造方法C#程序设计工程教程〔3〕新建约束T〔类型〕:new()69C#程序设计工程教程〔4〕基类约束T〔类型〕:<基类名>用来限制参数类型从特定的类中派生,例如:classA{publicvoidF1(){}}classB{publicvoidF2(){}}classC<S,T>whereS:AwhereT:B{//可以在类型为S的变量上调用F1//可以在类型为T的变量上调用F2}C#程序设计工程教程〔4〕基类约束T〔类型〕:<基类名>用来70C#程序设计工程教程〔5〕接口约束T〔类型〕:<接口名>表示类型参数必须是指定的接口或实现指定的接口。可以指定多个接口约束。约束接口也可以是泛型的。例如:interfaceIPrintable{voidPrint();}interfaceIComparable<T>{intComparableTo(Tv);}interface

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论