版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
C#面向对象编程基础学习笔记第一页,编辑于星期六:七点三十九分。第1页,共60页。3.1继承在2.1.5节,定义了一个描述个人情况的Person类。如需要描述一个雇员,当然可以从头开始定义Employee类用来描述雇员。但这样不能利用Person类中已定义的函数和数据。比较好的方法是以Person类为基类,派生出Employee类,Employee类继承了Person类的数据成员和函数成员,既Person类的数据成员和函数成员成为Employee类的成员。这个Employee类叫以Person类为基类的派生类,这是C#提出的方法。C#用继承的方法,实现代码的重用。第二页,编辑于星期六:七点三十九分。第2页,共60页。3.1.1派生类的声明格式
派生类的声明格式如下:
附加说明类修饰符class派生类名:基类名{类体}雇员类Employee定义如下:
classEmployee:Person{ privatestringdepartment; privatedecimalsalary; publicEmployee(stringName,intAge, stringD,decimalS):base(Name,Age) { department=D; salary=S; }
第三页,编辑于星期六:七点三十九分。第3页,共60页。publicnewvoidDisplay()//注意new{ base.Display();//访问基类的同名方法 Console.WriteLine(“部门:{0}薪金:{1}”, department,salary);}}主函数如下:classClass1{ staticvoidMain(string[]args) {EmployeeOneEmployee=newEmployee( “李四”,30,"计算机系",2000); OneEmployee.Display(); }}
第四页,编辑于星期六:七点三十九分。第4页,共60页。3.1.2隐藏基类方法
在派生类中,可以声明与基类完全相同的新方法,完全相同是指和基类方法的函数类型、函数名、参数类型和个数都相同。如上例中的方法Display()。这样做不算错误,但会导致编译器发出警告。如果增加new修饰符,表示认可,编译器不再发出警告。请注意,声明与基类完全相同新方法,并不是移走基类同名方法,只是在派生类中必须用如下格式访问基类中同名方法:base.Display();也就是说派生类的新方法隐藏了基类同名方法。
第五页,编辑于星期六:七点三十九分。第5页,共60页。3.1.3base关键字
base关键字用于从派生类中访问基类成员,它有两种基本用法:
在定义派生类的构造函数中,指明要调用的基类构造函数,由于基类可能有多个构造函数,根据base后的参数类型和个数,指明要调用哪一个基类构造函数。在派生类的方法中调用基类中被派生类隐藏的方法。
第六页,编辑于星期六:七点三十九分。第6页,共60页。3.1.4C#语言类继承特点
C#语言只允许单继承,即派生类只能有一个基类。
C#语言继承是可以传递的,如果C从B派生,B从A派生,那么C不但继承B的成员,还要继承A中的成员。派生类可以添加新成员,但不能删除基类中的成员派生类不继承基类的构造函数和析构函数。能继承基类的属性。派生类可以隐藏基类的同名成员,如果在派生类中隐藏了基类同名成员,基类该成员在派生类中就不能被直接访问,只能通过base.基类方法名访问。派生类对象也是其基类的对象,但基类对象却不一定是其派生类的对象。例如,前边定义的雇员类Employee是Person类的派生类,所有雇员都是Person类的成员,但很多Person类的成员并不是雇员,可能是学生、自由职业者、儿童等。因此C#语言规定,基类的引用变量可以引用其派生类对象,但派生类的引用变量不可以引用其基类对象。
第七页,编辑于星期六:七点三十九分。第7页,共60页。3.2类的成员
由于C#程序中每个变量或函数都必须属于一个类或结构,不能象C或C++那样建立全局变量,因此所有的变量或函数都是类或结构的成员。类的成员可以分为两大类:类本身所声明的以及从基类中继承来的。
第八页,编辑于星期六:七点三十九分。第8页,共60页。3.2.1类的成员类型
类的成员包括以下类型局部变量:在for、switch等语句中和类方法中定义的变量
字段:即类中的变量或常量,包括静态字段、实例字段、常量 和只读字段。方法成员:即类中的方法,包括静态方法和实例方法。
属性:按属性指定的get方法和set方法对字段进行读写。属 性本质上是方法。事件:代表事件本身,同时是事件处理函数的代表。索引指示器:允许象数组那样使用索引访问类中的数据成员。重载操作符:采用重载操作符的方法定义类中特有的操作。构造函数和析构函数。
第九页,编辑于星期六:七点三十九分。第9页,共60页。3.2.2类成员访问修饰符
访问修饰符有4种,用于指定类成员的可访问性:
Private:protected:public:Internal:内部成员只能在同一程序集中的文件中才是可以访问的,一般是同一个应用(Application)或库(Library)。
第十页,编辑于星期六:七点三十九分。第10页,共60页。3.3类的字段和属性
一般把类或结构中定义的变量和常量叫字段。属性不是字段,本质上是定义修改字段的方法,由于属性和字段的紧密关系,把它们放到一起叙述。
第十一页,编辑于星期六:七点三十九分。第11页,共60页。3.3.1静态字段、实例字段、常量和只读字段
见下例:publicclassTest{publicconstintintMax=int.MaxValue;//常量必须赋初值publicintx=0; //实例字段,每个实例创建不同xpublicreadonlyinty=0;//只读字段,每个实例创建不同ypublicstaticintcnt=0;//静态字段,所有实例共用一个cntpublicTest(intx1,inty1) //构造函数{ //intMax=0;错误,在构造函数不能修改常量 x=x1; //在构造函数允许修改实例字段 y=y1; //在构造函数允许修改只读字段 cnt++;//每创建一个对象都调用构造函数, //用此语句可以记录对象的个数}
第十二页,编辑于星期六:七点三十九分。第12页,共60页。publicvoidModify(intx1,inty1){ //intMax=0;和y=10;错误,不能修改常量和只读字段 x=x1; cnt=y1;}}classClass1{ staticvoidMain(string[]args){ TestT1=newTest(100,200); T1.x=40;//引用实例字段方法:实例名.实例字段名 Tt=0;//引用静态字段方法:类名.静态字段名 intz=T1.y; //引用只读字段 z=TMax; //引用常量}}第十三页,编辑于星期六:七点三十九分。第13页,共60页。3.3.2属性
C#语言支持组件编程,组件也是类,组件用属性、方法、事件描述。属性不是字段,但必然和类中的某个或某些字段相联系,属性定义了得到和修改相联系的字段的方法。C#中的属性更充分地体现了对象的封装性:不直接操作类的数据内容,而是通过访问器进行访问,借助于get和set方法对属性的值进行读写。访问属性值的语法形式和访问一个变量基本一样,使访问属性就象访问变量一样方便,符合习惯。在类的基本概念一节中,定义一个描述个人情况的类Person,其中字段name和age是私有字段,记录姓名和年龄,外部通过公有方法SetName和SetAge修改这两个私有字段。现在用属性来描述姓名和年龄。例子如下:
第十四页,编辑于星期六:七点三十九分。第14页,共60页。usingSystem;publicclassPerson{ privatestringP_name="张三";//P_name是私有字段 privateintP_age=12; //P_age是私有字段 publicvoidDisplay()//类的方法声明,显示姓名和年龄 { Console.WriteLine(“姓名:{0},年龄:{1}”, P_name,P_age); } publicstringName //定义属性Name { get{ returnP_name; } set{ P_name=value; } } publicintAge //定义属性Age { get{ returnP_age; } set{ P_age=value; } }}第十五页,编辑于星期六:七点三十九分。第15页,共60页。publicclassTest{ publicstaticvoidMain(){ PersonOnePerson=newPerson(); OnePerson.Name="田七";//通过set方法修改变量P_Name strings=OnePerson.Name;//通过get方法得到变量P_Name值
//下句错误Test不是Person派生类,不能修改Age属性 //OnePerson.Age=20; intx=OnePerson.Age;//通过定义属性,既保证了姓名 //和年龄按指定方法修改 OnePerson.Display();//语法形式和修改、 //得到一个变量基本一致,符合习惯}} 只有set访问器的属性值只能进行设置而不能读出,只有get访问器的属性值是只读的,不能改写,同时具有set和get访问器表明属性值的读写都是允许的。
第十六页,编辑于星期六:七点三十九分。第16页,共60页。3.4类的方法3.4.1方法的声明
方法的声明格式如下:方法修饰符返回类型方法名(形参列表){方法体}
3.4.2方法中参数的传递值参数,不含任何修饰符(值类型、引用类型不同)
引用参数,以ref修饰符声明(主要用于值类型)输出参数,以out修饰符声明(主要用于值类型)usingSystem;classg{publicinta=0;}//类定义
第十七页,编辑于星期六:七点三十九分。第17页,共60页。classClass1{ publicstaticvoidF1(refchari) //引用参数 { i='b'; } publicstaticvoidF2(chari)//值参数,形参类型为值类型 { i='d'; } publicstaticvoidF3(outchari) //输出参数 { i='e'; }publicstaticvoidF4(strings)//值参数形参类型为字符串{s="xyz";}//虽然字符串为引用类型,参数传递方式和值类型相同 publicstaticvoidF5(ggg)//值参数,形参类型为引用类型 { gg.a=20; }publicstaticvoidF6(refstrings) { s=“xyz”; }//引用参数,形参类型为字符串staticvoidMain(string[]args){ chara='c'; strings1="abc";第十八页,编辑于星期六:七点三十九分。第18页,共60页。 F2(a); //值参数,不能修改外部的a Console.WriteLine(a); //因a未被修改,显示c F1(refa); //引用参数,函数修改外部的a的值 Console.WriteLine(a); //a被修改为b,显示b Charj; F3(outj); //输出参数,结果输出到外部变量j Console.WriteLine(j); //显示e F4(s1);//值参数,参数类型是字符串,s1为字符串引用变量 Console.WriteLine(s1);//显示:abc,字符串s1不被修改 gg1=newg(); F5(g1);//值参数,但实参是一个类引用类型变量 Console.WriteLine(g1.a.ToString());//显示:20修改对象数据 F6(refs1);//引用参数,参数类型是字符串,s1为字符串引用变量 Console.WriteLine(s1);//显示:xyz,字符串s1被修改 }}第十九页,编辑于星期六:七点三十九分。第19页,共60页。数组参数,以params修饰符声明,数组参数使用params说明,如果形参表中包含了数组参数,那么它必须是参数表中最后一个参数,数组参数只允许是一维数组。usingSystem;classClass1{ staticvoidF(paramsint[]args) //数组参数 { Console.Write(“数组包含{0}个元素:”, args.Length); foreach(intiinargs) Console.Write("{0}",i); }第二十页,编辑于星期六:七点三十九分。第20页,共60页。staticvoidMain(string[]args){int[]a={1,2,3}; F(a); //实参为数组类引用变量a F(10,20,30,40);//等价于F(newint[]{10,20,30,40}) F(newint[]{60,70,80,90});//实参为数组类引用 F(); //等价于F(newint[]{}); F(newint[]{});//实参为数组类引用,数组无元素}}程序输出数组包含3个元素:123数组包含4个元素:10203040数组包含4个元素:60,70,80,90数组包含0个元素:数组包含0个元素:
第二十一页,编辑于星期六:七点三十九分。第21页,共60页。 方法的参数为数组时也可以不使用params,此种方法可以使用一维或多维数组,见下例:usingSystem;classClass1{ staticvoidF(int[,]args)//值参数类型为数组类引用变量 { Console.Write("数组包含{0}个元素:",args.Length); foreach(intiinargs) Console.Write("{0}",i); } staticvoidMain(string[]args) { int[,]a={{1,2,3},{4,5,6}}; F(a); //实参为数组类引用变量a//F(10,20,30,40);F();F(newint[,]{});这两种格式不能使用 F(newint[,]{{60,70},{80,90}});//实参为数组类引用 }}
第二十二页,编辑于星期六:七点三十九分。第22页,共60页。3.4.3静态方法和实例方法
用修饰符static声明的方法为静态方法
不管类生成或未生成对象,类的静态方法都可以被使用,使用格式为:类名.静态方法名。静态方法只能使用该静态方法所在类的静态数据成员和静态方法。这是因为使用静态方法时,该静态方法所在类可能还没有对象不用修饰符static声明的方法为实例方法
在类创建对象后,实例方法才能被使用,使用格式为:对象名.实例方法名。实例方法可以使用该方法所在类的所有静态成员和实例成员。例子如下:
第二十三页,编辑于星期六:七点三十九分。第23页,共60页。usingSystem;publicclassUseMethod{ privatestaticintx=0;//静态字段privateinty=1;//实例字段publicstaticvoidStaticMethod()//静态方法{ x=10; //正确,静态方法访问静态数据成员 //y=20;错误,静态方法不能访问实例数据成员}publicvoidNoStaticMethod()//实例方法{ x=10; //正确,实例方法访问静态数据成员y=20; //正确,实例方法访问实例数据成员}}第二十四页,编辑于星期六:七点三十九分。第24页,共60页。publicclassClass1{ publicstaticvoidMain(){ UseMethodm=newUseMethod();//使用静态方法格式为:类名.静态方法名 UseMethod.StaticMethod(); //使用实例方法格式为:对象名.实例方法名 m.NoStaticMethod();}}第二十五页,编辑于星期六:七点三十九分。第25页,共60页。3.4.4操作符重载
usingSystem;classComplex //复数类定义{ privatedoubleReal; //复数实部 privatedoubleImag; //复数虚部 publicComplex(doublex,doubley) //构造函数 { Real=x; Imag=y; } staticpublicComplexoperator-(Complexa) {return(newComplex(-a.Real,-a.Imag)); }//重载一元操作符
staticpublicComplexoperator+(Complexa,Complexb){ return(newComplex(a.Real+b.Real,a.Imag+b.Imag));}publicvoidDisplay(){ Console.WriteLine("{0}+({1})j",Real,Imag); }}第二十六页,编辑于星期六:七点三十九分。第26页,共60页。classClass1{ staticvoidMain(string[]args) {Complexx=newComplex(1.0,2.0); Complexy=newComplex(3.0,4.0); Complexz=newComplex(5.0,7.0); x.Display(); //显示:1+(2)j y.Display(); //显示:3+(4)j z.Display(); //显示:5+(7)j z=-x; //等价于z=opeator-(x) z.Display(); //显示:-1+(-2)j z=x+y; //即z=opeator+(x,y) z.Display(); //显示:4+(6)j }}第二十七页,编辑于星期六:七点三十九分。第27页,共60页。3.4.5this关键字
每个类都可以有多个对象,例如定义Person类的两个对象:PersonP1=newPerson("李四",30);PersonP2=newPerson("张三",40);因此P1.Display()应显示李四信息,P2.Display()应显示张三信息,但无论创建多少个对象,只有一个方法Display(),该方法是如何知道显示哪个对象的信息的呢?C#语言用引用变量this记录调用方法Display()的对象,当某个对象调用方法Display()时,this便引用该对象(记录该对象的地址)。
第二十八页,编辑于星期六:七点三十九分。第28页,共60页。3.5类的多态性
C#支持两种类型的多态性编译时的多态性
编译时的多态性是通过方法重载来实现的。
运行时的多态性
是在系统运行时,不同对象调用一个名字相同,参数的类型及个数完全一样的方法,会完成不同的操作。C#运行时的多态性通过虚方法实现。在类的方法声明前加上了virtual修饰符,被称之为虚方法,反之为非虚方法。
第二十九页,编辑于星期六:七点三十九分。第29页,共60页。usingSystem;classA{ publicvoidF() //非虚方法{ Console.Write("A.F"); }publicvirtualvoidG() //虚方法{Console.Write("A.G"); }}classB:A //A类为B类的基类{ newpublicvoidF()//隐藏基类的同名非虚方法F注意使用new{ Console.Write("B.F"); }publicoverridevoidG()//隐藏基类同名虚方法G使用override{ Console.Write("B.G"); }}第三十页,编辑于星期六:七点三十九分。第30页,共60页。classTest{ staticvoidF2(AaA) //注意,参数为A类引用变量{ aA.G(); }staticvoidMain(){Bb=newB();Aa1=newA();Aa2=b;//允许基类引用变量引用派生类对象a2引用派生类B对象ba1.F(); //调用基类A的非虚方法F(),显示A.Fa2.F(); //F()为非虚方法,调用基类A的F(),显示A.Fb.F(); //F()为非虚方法,调用派生类B的F(),显示B.Fa1.G();//G为虚方法,因a1引用基类A对象,调用基类A的G,显示A.Ga2.G();//G为虚方法,a2引用派生类B对象,调用派生类B的G,显示B.GF2(b);//实参为派生类B对象,AaA=b,调用派生类B的函数G,显示B.GF2(a1);//实参为基类A对象,调用A类的函数G(),显示A.G}}第三十一页,编辑于星期六:七点三十九分。第31页,共60页。3.6作用域作用域又称作用范围,它指的是标识符可以使用的范围。C#语言中,类(或结构)成员的作用域是整个类;方法内声明的局部变量(含局部常量)的作用域从它的声明开始延续到包含它的块尾。第三十二页,编辑于星期六:七点三十九分。第32页,共60页。3.6.1类成员的作用域C#语言中类成员的作用域是整个类。因此,类定义中,成员之间的顺序是任意的。例如:classTest{publicvoidMyMethod(){num++;Console.WriteLine(num);}privateintnum=0;}上例就把字段的声明放在类体的尾部,而在前面定义了使用该字段的方法。第三十三页,编辑于星期六:七点三十九分。第33页,共60页。3.6.2局部变量的作用域方法体内声明的变量称为局部变量,局部变量的作用域从它的声明开始延续到包含它的块尾。例如:voidf1(){inti=100; //变量i作用域的起始处if(i>0){...intj=10; //变量j作用域的起始处...} //变量j作用域的结束处} //变量i作用域的结束处第三十四页,编辑于星期六:七点三十九分。第34页,共60页。3.7抽象类和抽象方法
抽象类只能作为其他类的基类,它不能直接被实例化。
抽象类允许包含抽象方法,虽然这不是必须的。抽象方法用abstract修饰符修饰。
抽象类不能同时又是密封的。
抽象类的基类也可以是抽象类。如果一个非抽象类的基类是抽象类,则该类必须通过隐藏来实现所有继承而来的抽象方法,包括其抽象基类中的抽象方法,如果该抽象基类从其他抽象类派生,还应包括其他抽象类中的所有抽象方法。
请看下面的示例:
第三十五页,编辑于星期六:七点三十九分。第35页,共60页。usingSystem;abstractclassFigure//抽象类定义,表示一个抽象图形{ protecteddoublex=0,y=0; publicFigure(doublea,doubleb) { x=a; y=b; }
//抽象方法,无实现代码,抽象图形无法计算面积publicabstractvoidArea();}classSquare:Figure //类Square定义,矩形类{ publicSquare(doublea,doubleb):base(a,b) {}publicoverridevoidArea()//不能使用new,必须用override{ Console.WriteLine("矩形面积是:{0}",x*y);}}第三十六页,编辑于星期六:七点三十九分。第36页,共60页。classCircle:Figure //类Circle定义,圆类{ publicCircle(doublea):base(a,a) {}publicoverridevoidArea(){Console.WriteLine("圆面积是:{0}",3.14*x*y);}}classClass1{ staticvoidMain(string[]args) { Squares=newSquare(20,30); Circlec=newCircle(10); s.Area(); c.Area(); }}程序输出结果为:矩形面积是:600圆面积是:314第三十七页,编辑于星期六:七点三十九分。第37页,共60页。3.8密封类和密封方法
有时候,我们并不希望自己编写的类被继承。或者有的类已经没有再被继承的必要。C#提出了一个密封类(sealedclass)的概念,帮助开发人员来解决这一问题。密封类在声明中使用sealed修饰符,这样就可以防止该类被其他类继承。如果试图将一个密封类作为其他类的基类,C#编译器将提示出错。理所当然,密封类不能同时又是抽象类,因为抽象总是希望被继承的。C#还提出了密封方法(sealedmethod)的概念。方法使用sealed修饰符,称该方法是一个密封方法。在派生类中,不能重新定义基类中的密封方法。
第三十八页,编辑于星期六:七点三十九分。第38页,共60页。3.9静态类和静态类成员
C#2.0中的类可以声明为静态的,例如staticclassMyClass{}表示MyClass类是静态的。静态类仅包含静态成员,不能使用new创建静态类的对象,静态类必须是密封的,不能有构造函数。静态类在加载包含该类的程序或命名空间时由CLR自动加载。
第三十九页,编辑于星期六:七点三十九分。第39页,共60页。3.10C#2.0中的分部类
分部类可将类、结构或接口的定义拆分到两个或多个源文件中。若要拆分类定义,被拆分类的每一部分的定义前边都要用partial关键字修饰,类的每一部分定义可以存到不同源文件中,编译应用程序时将把所有部分组合起来。VS2005生成的Windows应用程序框架采用了分部类的概念,Form1类用分部类方法分成两部分,在不同文件中,其中Form1.Designer.cs文件是由VS2005自动生成的代码,自己编写的代码应放到Form1.cs文件中。
第四十页,编辑于星期六:七点三十九分。第40页,共60页。3.11接口
在接口中可以声明方法、属性、索引指示器和事件,接口中并不提供它们的实现。因此接口是函数成员声明的集合。如果类或结构从一个接口派生,则这个类或结构负责实现该接口中所声明的所有函数成员。一个接口可以继承多个接口,而一个类或结构可以实现多个接口。由于C#语言不支持多继承,因此,如果某个类需要继承多个类的行为时,只能使用多个接口加以说明。第四十一页,编辑于星期六:七点三十九分。第41页,共60页。3.11.1接口声明
publicinterfaceIexample { //索引指示器声明 stringthis[intindex]{get;set;} eventEventHandlerE; //事件声明voidF(intvalue); //方法声明stringP{get;set;} //属性声明} 首先接口成员只能是方法、属性、索引指示器和事件。所有接口成员都不能包括实现。接口成员声明不能包含任何修饰符,接口成员默认访问方式是public。
第四十二页,编辑于星期六:七点三十九分。第42页,共60页。3.11.2接口的继承 类似于类的继承性,接口也有继承性。派生接口继承了基接口中的函数成员说明。接口允许多继承,一个派生接口可以没有基接口,也可以有多个基接口。在接口声明的冒号后列出被继承的接口名字,多个接口名之间用分号分割。例子如下:
第四十三页,编辑于星期六:七点三十九分。第43页,共60页。usingSystem;interfaceIControl{ voidPaint(); }//继承了接口Icontrol的方法Paint()interfaceITextBox:Icontrol{ voidSetText(stringtext); }//继承了接口Icontrol的方法Paint()interfaceIListBox:Icontrol{ voidSetItems(string[]items); }//继承了接口Icontrol、ITextBox和IListBox的方法interfaceIComboBox:ITextBox,IListBox{ } //可以声明新方法
第四十四页,编辑于星期六:七点三十九分。第44页,共60页。3.11.3类对接口的实现
类实现接口的本质是,用接口规定类应实现哪些函数成员。用类来实现接口时,接口的名称必须包含在类声明中的基类列表中。
在类的基本概念一节中,定义一个描述个人情况的类Person,从类Person可以派生出其他类,例如:工人类、公务员类、医生类等。这些类有一些共有的方法和属性,例如工资属性。一般希望所有派生类访问工资属性时用同样变量名。该属性定义在类Person中不合适,因为有些人无工资,如小孩。如定义一个类作为基类,包含工资属性,但C#不支持多继承。可行的办法是使用接口,在接口中声明工资属性。工人类、公务员类、医生类等都必须实现该接口,也就保证了它们访问工资属性时用同样变量名。例子如下:
第四十五页,编辑于星期六:七点三十九分。第45页,共60页。usingSystem;publicinterfaceI_Salary//接口{ decimalSalary//属性声明 { get; set; }}publicclassPerson//参见1.9.2节Person类定义{…}//但age的set访问权限要改为public//Person类是基类,I_Salary是接口publicclassEmployee:Person,I_Salary{//不同程序员完成工人类、医生类等,定义工资变量名称可能不同privatedecimalsalary;publicnewvoidDisplay(){ base.Display(); Console.WriteLine("薪金:{0}",salary);}第四十六页,编辑于星期六:七点三十九分。第46页,共60页。//工人类、医生类等都要按以下方法实现属性Salary,保证工资属性同名publicdecimalSalary { get{ returnsalary; } set{ salary=value; } }}publicclassTest{ publicstaticvoidMain(){ EmployeeS=newEmployee(); S.Name="田七";//修改属性Name S.Age=20;//修改属性Age S.Salary=2000;//修改属性Salary S.Display();}}
第四十七页,编辑于星期六:七点三十九分。第47页,共60页。 如果类继承了某个接口,类也隐式地继承了该接口的所有基接口,不管这些基接口有没有在类声明的基类表中列出。因此,如果类从一个接口派生,则这个类负责实现该接口及该接口的所有基接口中所声明的所有成员。
第四十八页,编辑于星期六:七点三十九分。第48页,共60页。3.12委托类型C#的一个新的引用数据类型:代表类型,也翻译为委托类型。在功能上它类似C语言的函数指针,目的是通过创建代表类型对象去调用函数。使用代表类型的第一步,是从delegate类派生出一个代表类型,指明这个代表类型对象要代表的函数的返回值类型,参数的个数及类型,因此C#中的代表类型是类型安全的。声明一个代表类型格式如下:修饰符delegate函数返回类型定义的代表标识符(函数形参列表);
例如我们可以声明一个能代表返回类型为int,无参数的函数的代表类型,类型名为MyDelegate,类型声明如下,只能代表返回类型为int,无参数的函数
publicdelegateintMyDelegate(); 声明了代表类型MyDelegate,可创建代表类型MyDelegate的对象,用这个对象去代表一个静态方法或非静态的方法,所代表的方法必须为int类型,无参数。看下面的例子:
第四十九页,编辑于星期六:七点三十九分。第49页,共60页。usingSystem;delegateintMyDelegate();//声明一个代表类型注意位置publicclassMyClass{ publicintInstanceMethod()//非静态int类型,无参数方法{ Console.WriteLine("调用了非静态的方法。"); return0; }staticpublicintStaticMethod()//静态int类型无参数方法{ Console.WriteLine("调用了静态的方法。"); return0; }}publicclassTest{ staticpublicvoidMain(){ MyClassp=newMyClass();//用new建立代表类型MyDelegate对象,对象d代表了方法InstanceMethodMyDelegated=newMyDelegate(p.InstanceMethod); //参数是被代表的方法
第五十页,编辑于星期六:七点三十九分。第50页,共60页。d();//因对象d代表了方法InstanceMethod,调用非静态方法//下条语句对象d代表了方法StaticMethod,参数是被代表的方法d=newMyDelegate(MyClass.StaticMethod); d();//因对象d代表了方法StaticMethod,用此方式调用这个静态方法}}程序的输出结果是:调用了非静态的方法。调用了静态的方法。第五十一页,编辑于星期六:七点三十九分。第51页,共60页。3.13事件
3.13.1事件驱动
事件是C#语言内置的语法,可以定义和处理事件,为使用组件编程提供了良好的基础。
Windows应用程序和dos程序的最大不同是采用事件驱动方式工作,也叫消息驱动。dos程序如要从键盘输入数据,则要独占键盘等待用户输入,如用户不输入,则CPU一直执行键盘输入程序,等待用户输入,即dos程序独占外设和CPU。Windows操作系统是一个多任务的操作系统,允许同时运行多个程序,它不允许任何一个程序独占外设,如键盘、鼠标等,所有运行程序共享外设和CPU,各个运行程序都要随时准备从外设接受命令,执行命令。因此必须由Windows操作系统统一管理各种外设。
第五十二页,编辑于星期六:七点三十九分。第52页,共60页。 Windows把用户对外设的动作都看作事件(消息),如单击鼠标左键,发送单击鼠标左键事件,用户按下键盘,发送键盘被按下的事件等。Windows操作系统统一负责管理所有的事件,根据具体情况把事件发送到相应运行程序,而各个运行程序自动用一个函数响应事件,这个函数叫事件处理函数。这种方法叫事件驱动。Windows操作系统在window.h文件中预定义了若干事件。在Form类和控件类中都定义了WndProc方法可截获Windows消息,这是一个虚函数。在它们的派生类中可重写WndProc方法,截获Windows消息,见下例,方法中Message是一个结构,m.Msg为事件编号,m.Wparam和m.LParam是事件的附加信息,事件不同,意义也不同。
第五十三页,编辑于星期六:七点三十九分。第53页,共60页。protectedoverridevoidWndProc(refMessagem){base.WndProc(refm);//调用基类事件处理函数if(m.Msg==0x0112&&(int)m.WParam==0xf060){…} //自定义处理事件代码}第五十四页,编辑于星期六:七点三十九分。第54页,共60页。3.13.2事件的声明
usingSystem;publicdelegatevoidChangedEvent(objectsender,EventArgse); //代表类声明publicclassPerson{publ
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 光伏买卖合同范本
- 广州公积金 租赁合同
- 韩国租房合同模板
- 合同到期自我评价个人总结简短
- 2024市旧机动车买卖合同
- 智慧交警建设方案
- 全国造价工程师注册管理系统详解
- 2024电器产品代理合同
- 2024制造行业合同管理系统解决方案
- 2024个人房屋装修合同范文
- 中央企业商业秘密安全保护技术指引2015版
- 螺旋果蔬榨汁机的设计
- 《脊柱整脊方法》
- 会计与财务管理专业英语智慧树知到答案章节测试2023年哈尔滨商业大学
- 广东省2020年中考英语试题【含答案】
- 0417 教学能力大赛 公共基础《英语 》教学实施报告 电子商务专业
- 拦砂坝施工设计方案
- 校园及周边重点人员排查情况表
- GB/T 16734-1997中国主要木材名称
- 方太销售及市场营销管理现状
- 蔬菜栽培的季节与茬口安排-陇东学院教学提纲
评论
0/150
提交评论