面向对象
继承——————子承父业
继承是软件(代码)复用的一种形式。使用继承可以复用现有类的数据行为(方法),为其赋予新的功能(方法)从而创建出新类。复用能节省程序开发的时间,能重用经过实践检验和调试的高质量代码,从而提高系统的质量。
继承的定义和使用
在现有的类(也称是直接基类,父类)上创建新类(称为派生类,子类)的处理过程称为继承。
派生类能自动获得基类的除构造函数和析构函数以外的所有成员,可以在派生类中添加新的属性和方法扩展其功能。
语法为:
<访问修饰符> class 派生类名:基类名
{
类的成员。(类的代码)
}
在实际中一个类的对象也是另一个类的对象。
如:
教师类和学生类都可以从人这个类派生,而讲师,教授可以从教师类中派生,研究生和本科生可以从学生类派生而得到。
如:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication2 { public class Person { private string _id;//声明身份证号码字段 public string Id//声明身份证号码属性 { get//get访问器,得到身份证号码字段的值 { return _id; } set//set访问器设置身份证号码字段的值 { _id = value; } } private string _name;//声明姓名字段 public string Name//声明姓名属性 { get { return _name; } set { _name = value; } } private int _age;//声明年龄字段 public int Age//声明年龄属性 { get { return _age; } set { _age = value; } } private string _gender;//声明性别字段 public string Gender//声明性别属性 { get { return _gender; } set { _gender = value; } } public Person()//定义无参的构造函数 { } public Person(string name, int age, string gender)//定义3个参数的构造函数 { _name = name; _age = age; _gender = gender; } public void Display()//用于输出Person对象的姓名,性别,和年龄信息 { Console.WriteLine("{0}是{1}性,年龄为{2}",this._name,this._gender,this._age); } } public class Student : Person//创建派生类,派生自Person { private string _class;//定义表示学生所在班级的字段_class public string Class//定义获取或设置班级信息的属性Class { get { return _class; } set { _class = value; } } private string _department;//定义学生所属系的字段 public string Department//定义学生所属系的属性 { get { return _department; } set { _department = value; } } private string _no;//定义表示学生学号的字段 private string No//定义学好的属性 { get { return _no; } set { _no = value; } } public Student()//无参构造函数 { } public void Study()//定义派生类独有的方法Studuy,表示学生负有学习的任务 { Console.WriteLine("学生在学校学习!"); } } class Program { static void Main(string[] args) { Person objperson = new Person("张三",18,"男");//创建Person的对象objperson objperson.Display();//调用Display方法显示对象信息 Student objstudent = new Student();//创建Student的对象objstudent objstudent.Name = "李四"; objstudent.Age = 18; objstudent.Gender = "男"; objstudent.Class = "2016软件工程专业1班"; objstudent.Display();//访问基类Display方法 objstudent.Study();//调用派生类方法 Console.ReadKey(); } } }
运行结果
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication2 { public class Person { private string _id;//声明身份证号码字段 public string Id//声明身份证号码属性 { get//get访问器,得到身份证号码字段的值 { return _id; } set//set访问器设置身份证号码字段的值 { _id = value; } } private string _name;//声明姓名字段 public string Name//声明姓名属性 { get { return _name; } set { _name = value; } } private int _age;//声明年龄字段 public int Age//声明年龄属性 { get { return _age; } set { _age = value; } } private string _gender;//声明性别字段 public string Gender//声明性别属性 { get { return _gender; } set { _gender = value; } } public Person()//定义无参的构造函数 { } public Person(string name, int age, string gender)//定义3个参数的构造函数 { _name = name; _age = age; _gender = gender; } public void Display()//用于输出Person对象的姓名,性别,和年龄信息 { Console.WriteLine("{0}是{1}性,年龄为{2}",this._name,this._gender,this._age); } } public class Student : Person//创建派生类,派生自Person { private string _class;//定义表示学生所在班级的字段_class public string Class//定义获取或设置班级信息的属性Class { get { return _class; } set { _class = value; } } private string _department;//定义学生所属系的字段 public string Department//定义学生所属系的属性 { get { return _department; } set { _department = value; } } private string _no;//定义表示学生学号的字段 private string No//定义学好的属性 { get { return _no; } set { _no = value; } } public Student()//无参构造函数 { } public void Study()//定义派生类独有的方法Studuy,表示学生负有学习的任务 { Console.WriteLine("学生在学校学习!"); } } class Teacher : Person { private string _tid; public string Tid { get { return _tid; } set { _tid = value; } } public string _course; public string Course { get { return _course; } set { _course = value; } } public void Teaching() { Console.WriteLine("教师在学校教课"); } } public class DoubleStudent : Student { private string _sndBachelor; public string SndBachelor { get { return _sndBachelor; } set { _sndBachelor = value; } } public DoubleStudent() { } public void UsaBachelor() { Console.WriteLine("正在攻读美国Fort Hays 大学学位"); } } class Program { static void Main(string[] args) { Teacher objTeacher = new Teacher();//创建Teacher类的对象 objTeacher.Name = "Martin"; objTeacher.Age = 35; objTeacher.Gender = "男"; objTeacher.Display(); objTeacher.Teaching(); Console.WriteLine("DoubleStudent"); DoubleStudent objspecial = new DoubleStudent(); objspecial.Name = "Bliss"; objspecial.Age = 18; objspecial.Gender = "女"; objspecial.Display(); objspecial.Study(); objspecial.UsaBachelor(); Console.ReadKey(); } } }
运行结果
继承的特性
1,继承的可传递性
如果C从B中派生,B又从A中派生,那么C不仅继承了B中声明的成员,同样也继承了A中的成员。派生类是对基类的扩展,在派生类中可以添加新成员,但不能去除已经继承的成员。
构造函数和析构函数不能被继承。除此以外的其他成员,不论对它们定义了怎样的访问方式,都能被继承。基类中成员的访问方式只能决定派生类能否访问它们。派生类如果定义了与继承而来的成员同名的新成员,就可以覆盖已继承的成员。但这并不意味派生类删除了这些成员,只是不能再访问这些成员。
2,继承的单一性
继承的单一性是指派生类只能从一个基类中继承,不能同时继承多个基类。C#不支持类的多重继承,也就是说儿子只能有一个亲生父亲,不能同时拥有多个亲生父亲,多重继承可以通过接口实现。
3,继承中的访问修饰符
C#中的访问修饰符有public,protected,private,internal和protected internal等5种,可以使用这些访问修饰符指定5个可访问性级别:public, protected,internal,protected internal和private。在继承时各个访问修饰符的访问权限如表所示
访问修饰符 | 类内部 | 派生类 |
public | 访问权限不受限制 | 不受限制 |
protected | 访问仅限于包含类或从包含类派生的类型 | 可以访问 |
internal | 访问仅限于当前项目 | 可以访问 |
protected internal | 访问仅限于从包含类派生的当前项目或类型 | 可以访问 |
private | 访问仅限于包含类型 | 不可访问 |
基类中的成员如果使用public修饰,任何类都可以访问;如果用privatc修饰,它将作为私有成员,只有类本身可以访问,其他任何类都无法访问。在C#中,我们使用protected修饰符,使用这个访问修饰符的成员可以被其派生类访问,而不允许其他非派生类访问。
base和this关键字
通过上面的介绍可以知道,基类中只能被public,protected,internal修饰的成员才可以被访问,这些成员包括任何基类的字段,属性,方法和索引器,但是基类的构造函数和析构函数是不能被继承的。如果要继承基类的构造函数,必须使用base关键字来实现。C#中的base关键字代表基类,使用base关键字可以调用基类的构造函数,属性和方法。使用base关键字调用基类构造函数的语法如下:
派生类构造函数:base(参数列表)
例如:
public Student(string name,int age,string gender):base(name,age ,gender)//无参构造函数 { }
使用base关键字调用基类方法的语法如下:
base.基类方法();
public void Study()//定义派生类独有的方法Studuy,表示学生负有学习的任务 { Console.WriteLine("学生在学校学习!"); base.Display();//使用base关键字调用基类方法 }
相对于base来说,this关键字是引用类的当前实例。例如:
public Person(string name, int age, string gender)//定义3个参数的构造函数 { this. _name = name; this._age = age; this. _gender = gender; }
this关键字引用类的当前实例,还可用做扩展方法的第一个参数的修饰符,this关键字还可以调用自己的构造方法。使用this关键字可以使代码的编写简单化,不容易出错。在类的方法里输入this关键字,在后面输入一个“.”符号后,系统就会把本类所能调用的非静态方法和变量都显示出来供选择,这样可以提高编写代码的效率。
派生类继承基类的属性和方法,使创建派生类变得简单,可实现代码的重用。继承还有个重要的特性,就是基类对象可以引用派生类对象,也就是派生类对象可以赋值给基类对象。
如:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication2 { public class Person { private string _id; public string Id { get { return this._id; } set { this._id=value; } } private string _name; public string Name { get { return this._name; } set { this._name=value; } } private int _age; public int Age { get { return this._age; } set { this._age=value; } } private string _gender; public string Gender { get { return this._gender; } set { this._gender=value; } } public Person() { } public Person(string name,int age,string gender) { this._name=name; this._age=age; this._gender=gender; } public void Display() { Console.WriteLine("{0}是{1}性,年龄为{2}",this._name,this._gender,this._age); } } public class Student:Person { private string _class; public string Class { get { return _class; } set { _class=value; } } private string _department; public string Departmtent { get { return this._department; } set { this._department=value; } } private string _no; public string No { get { return this._no; } set { this._no=value; } } public Student() { } public Student(string name,int age,string gender):base(name,age,gender) { } public void Study() { Console.WriteLine("学生在学习呢!"); } } class Program { static void Main(string[] args) { Person objPerson = new Person("刘六",18,"男"); Console.WriteLine("基类Person对象的Display方法"); objPerson.Display(); Student objstudent = new Student("王七",18,"男"); objstudent.Class = "2016软件工程专业1班"; Console.WriteLine("派生类调用基类Person对象的Displauy方法:"); objstudent.Display(); Console.WriteLine("派生类调用自己的Study方法:"); objstudent.Study(); Console.WriteLine("基类对象引用派生类实例"); Person person = new Person(); person = objstudent; ((Student)person).Study(); Console.ReadKey(); } } }
运行结果
面向对象——多态
"多态“最早用于生物学,指同一种族的生物体具有相同的特性。
比如青蛙小的时候是蝌蚪,长大了就是青蛙,同是一种生物但是有不同的表现形式。
C#中,多态的定义是:同一操作作用于不同的类的对象,不同的类的对象进行不同的执行,最后产生不同的结果。
多态的实现
C#中支持基于接口的多态和基于继承的多态,基于继承的多态设计在基类中定义方法,并在派生类中重写方法。多态和重写是紧密联系的,重写是实现多态的重要手段,重写基类方法就是修改它的实现,或者说在派生类中对继承的基类方法的重新编写。在基类中用virtual关键字声明的方法(叫做虚拟方法)在派生类中可以重写,虚拟方法语法如下;
访问修饰符 virtual 返回类型 方法名()
{
//方法体
}
在派生类中使用override关键字来声明重写,以实现对基类中虚拟方法的修改或重新编写。
例如:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication2 { public class Person { private string _id; public string Id { get { return this._id; } set { this._id=value; } } private string _name; public string Name { get { return this._name; } set { this._name=value; } } private int _age; public int Age { get { return this._age; } set { this._age=value; } } private string _gender; public string Gender { get { return this._gender; } set { this._gender=value; } } public Person() { } public Person(string name,int age,string gender) { this._name=name; this._age=age; this._gender=gender; } public virtual void Display() { Console.WriteLine("{0}是{1}性,年龄为{2}",this._name,this._gender,this._age); } } public class Student:Person { private string _class; public string Class { get { return _class; } set { _class=value; } } private string _department; public string Departmtent { get { return this._department; } set { this._department=value; } } private string _no; public string No { get { return this._no; } set { this._no=value; } } public Student() { } public Student(string name,int age,string gender):base(name,age,gender) { this._class = "三班"; this._department = "建筑系"; this._no = "141020"; } public void Study() { Console.WriteLine("学生在学习呢!"); } public override void Display() { base.Display(); Console.WriteLine("学生在学习呢!"); } } class Program { static void Main(string[] args) { Person objPerson = new Person("刘六",18,"男"); Console.WriteLine("基类Person对象的Display方法"); objPerson.Display(); Student objstudent = new Student("王七",18,"男"); objstudent.Class = "2016软件工程专业1班"; Console.WriteLine("Student对象的Display方法"); objstudent.Display(); Console.ReadKey(); } } }
方法的重载,重写和隐藏
在基类和派生类中可以存在同名方法,这些同名的方法可以为重载,重写和隐藏等3种类型。
1.重载
重载是在同一作用域内发生的(比如一个类里面),定义一系列同名方法,但是方法的参数列表不同,就是签名不同,签名由方法名和参数组成。通过传递不同的参数来决定到底调用哪一个同名方法,返回值类型不同不能构成重载,因为签名不包括返回值。
2.重写
基类方法中使用virtual关键字声明的方法和派生类中使用override关键字声明的方法名称相同,参数列表也相同,就是基类方法和派生类方法的签名相同,实现了派生类重写基类中的同名方法。
3.隐藏
基类中的方法不声明为virtual(默认为非虚方法),在派生类中声明与基类同名时,需使用new关键字,以隐藏基类同名的方法。
例如:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication2 { public class Person { public virtual void Display() { Console.WriteLine("这是一个人"); } public void Display(string name) { this.Display(); Console.WriteLine("这个人的名字叫{0}",name); } } public class Student:Person { public override void Display() { base.Display(); Console.WriteLine("学生在学习呢!"); } public new void Display(string name) { Console.WriteLine("这个方法隐藏了基类的方法"); } } class Program { static void Main(string[] args) { Console.ReadKey(); } } }
统一的接口—————接口
接口是面向对象编程的一个重要技术,在C#中负责实现多重继承。一个接口定义一个协议,实现接口的类或结构必须遵守其协定。
接口的定义
接口是用来描述一种程序的规定,可定义属于任何类或结构的一组相关行为。接口由方法,属性,事件,索引器或这4种成员类型的任何组合构成。
接口不能包含常数,字段,运算符,实例构造函数,析构函数或类型,也不能包含任何种类的静态成员。
接口的成员一定是公共的。
定义接口的语法如下:
<访问修饰符>interface 接口名
{
//接口的主体
}
接口不能包含其所定义的成员的任何实现语句,接口只指定实现该接口的类或必须提供的成员。
接口的实现
定义了接口后,就要在类或结构中实现。C#中通常把派生类和基类的关系称为继承,类和接口的关系称为实现。实现接口的语法和继承类一样,都有“:”,接口中的方法在类中实现时不是重载,不需要使用override关键字。
接口中不能定义构造函数,所以接口不能实例化。
例如:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication2 { interface IPoint { int x { get; set; } int y { get; set; } } class Point : IPoint { private int px; private int py; public Point(int x, int y) { px = x; py = y; } public int x { get { return px; } set { py = value; } } public int y { get { return py; } set { py = value; } } } class Program { static void Main(string[] args) { Point p = new Point(5, 30); Console.Write("新创建的Point点的坐标是:"); Console.WriteLine("x={0},y={1}",p.x,p.y); Console.ReadKey(); } } }
再次进行扩展
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication2 { interface IPerson { void DoWork();//表示person在做工作 void DoExercise();//表示person锻炼身体 } public class Person : IPerson { private string _id; public string Id { get { return _id; } set { _id = value; } } private string _name; public string Name { get { return _name; } set { _name = value; } } private int _age; public int Age { get { return _age; } set { _age = value; } } private string _gender; public string Gender { get { return _gender; } set { _gender = value; } } public Person() {} public Person(string name, int age, string gender) { this._name = name; this._age = age; this._gender = gender; } public void DoWork() { Console.WriteLine("{0}每天的任务是工作",this._name); } public void DoExercise() { Console.WriteLine("{0}每天下午参加体育锻炼",this._name); } public void Diplay() { Console.WriteLine("{0}是{1}性,年龄为{2}",this._name,this._gender,this._age); } } class Program { static void Main(string[] args) { Person p1 = new Person("Johnson",28,"男"); p1.Diplay(); p1.DoWork(); p1.DoExercise(); Console.ReadKey(); } } }
接口的继承
C#中的派生类只有一个基类,不支持类的多重继承,但可以继承多个接口,通过接口实现多继承。
其实接口就是为实现多继承产生的。在C#中接口可以多继承,接口之间可以相互继承,普通类和抽象类可以继承自接口。一个类可以同时继承一个类和多个接口,但是接口不能继承类。
抽象类和抽象方法
抽象类:简单的说就是用来描述共性的类就是抽象类,(抽象类是对类的抽象,类是对对象的抽象)抽象类中不考虑具体的实现,只确定必须具有的行为,即确定抽象方法。
包含抽象方法的类就是抽象类,抽象类和抽象方法声明使用abstract关键字。语法如下:
<访问修饰符>abstract class 抽象类名
{
<访问修饰符> abstract 返回类型 方法名();
}
实现抽象方法
C#中通过方法重写来实现抽象方法。当一个抽象基类派生一个派生类时,派生类将继承基类的所有特征,重新实现所有的抽象方法。在派生类中实现基类的抽象方法,是使用override关键字来重写基类方法。
例如:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication2 { public abstract class Employee { public abstract void Display(); } public class Manager : Employee { private string name; public Manager(string name) { this.name = name; } public override void Display() { Console.WriteLine("Name:"+name); } } class Program { static void Main(string[] args) { Manager obj = new Manager("Johnson"); obj.Display(); Console.ReadKey(); } } }
接口,类和抽象类
一个类可以同时继承类和接口,或者抽象类和接口,抽象类和类不能在一个类的继承列表中同时出现。如果派生类同时继承类或抽象类和接口,一定要把类或者抽象类写在前面,接口写在后面,类名和接口名用“,”隔开,接口没有先后顺序。每一种继承都要根据各自的规则去实现。
接口与抽象类的区别:
1,抽象类是一个不完全的类,需要通过派生类来完善它。
2,接口只是对类的约束,它仅仅承诺了类能够调用的方法。
3,一个类一次可以实现若干个接口。但一个类只能继承一个基类。
4,抽象类只需派生类实现它的抽象方法,接口要求必须实现它的所有成员。在实际编程中,接口的使用要比抽象类广泛得多。
密封类
与抽象类相反的是,C#支持创建密封类,密封类是不能当做基类的类。其他的类不能从此类派生,从而保证了密封类的密封性和安全性。在C#中使用sealed关键字创建密封类。
如:
public selaed class Animal
{
public Animal()
{
Console。WriteLine(“Animal被构造”);
}
}
设计类的时候,通常情况下是不需要将类设置为密封类的,因为密封类会让类的扩展性非常差,这个类也无法再次扩展和派生。但是出于某种目的,当程序块只需要完成某些特定的功能或者在商业上为保密,就可以使用密封类对类进行密封,以保证类的可靠性。
委托,事件和索引器
委托和事件是C#中两个比较复杂的概念。
委托
委托也叫代理,就是把事情交付给别人去办,如委托律师代理打官司。
C#中如果将一个方法委托给一个对象,这个对象就可以全权代理这个方法的执行。使用委托首先要定义委托,声明委托能代理什么类型的方法,定义委托的语法如下:
<访问修饰符> delegate 返回类型 委托名();
从上面不难看出定义委托和定义方法类似。委托没有具体的实现体,委托能够代表什么样的方法由它的返回值类型和参数列表决定。如定义如下委托:
public delegate void StuDelegate(string name);
使用stuDelegate委托代表的只可以是没有返回值,且参数为一个字符串的方法。
定义了委托之后就要使用委托,首先要实例化委托。实例化委托就是将其指向某个方法,即调用委托的构造函数,并将相关联的方法作为参数传递,然后通过调用委托,执行相关方法的代码,实现委托。
如:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication2 { class Test { public static bool SortArray(int[] array) { for (int i = array.GetUpperBound(0); i >= 0; i--) { for (int j = 0; j <= i; j++) { if (array[j] <= array[i]) { Swap(ref array[j], ref array[i]); } } } return true; } static void Swap(ref int x, ref int y) { int temp = x; x = y; y = temp; } } class Program { public delegate bool SortDelegate(int[] x); static void Main(string[] args) { int[] arr = new int[] { 8, 9, 5, 7, 2, 1, 4, 5, 6 }; Console.WriteLine("排顺序前的数组元素:"); foreach (int i in arr) { Console.WriteLine("{0}",i); } SortDelegate mydelegate; mydelegate = new SortDelegate(Test.SortArray); mydelegate(arr); Console.WriteLine("排顺序后的数组元素:"); foreach (int i in arr) { Console.WriteLine("{0}", i); } Console.ReadKey(); } } }
使用Lambda表达式运行结果不变
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication2 { class Program { public delegate bool SortDelegate(int[] x); static void Main(string[] args) { int[] arr = new int[] { 8, 9, 5, 7, 2, 1, 4, 5, 6 }; Console.WriteLine("排顺序前的数组元素:"); foreach (int i in arr) { Console.WriteLine("{0}",i); } SortDelegate mydelegate = array => { for (int i = array.GetUpperBound(0); i >= 0; i--) { for (int j = 0; j <= i; j++) { if (array[j] <= array[i]) { int temp = array[j]; array[j] = array[i]; array[i] = temp; } } } return true; }; mydelegate(arr); Console.WriteLine("排顺序后的数组元素:"); foreach (int i in arr) { Console.WriteLine("{0}", i); } Console.ReadKey(); } } }
索引器
索引器允许类或结构的实例就像数组一样进行索引。索引器类似于属性,不同之处在于它们的访问器采用的参数。索引器主要用于封装内部集合或数组的类中。索引器类似于字典中的检索,在字典中可以进行拼音检索和部首检索等方式查找汉子,索引器可以根据需要设定不同的检索方式快速查找类或结构的实例。索引器表示法不仅简化了客户端应用程序的语法,还使其他开发人员能够更加直观地理解类及其用途。要声明类或结构上的索引器,应使用关键字this如:
public int this[int index]
{
}
例如:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication2 { class DayCollection { string[] days = { "Sun", "Mon", "Tues", "Wed", "Thurs", "Fri", "Sat" }; private int GetDay(string testDay) { int i = 0; foreach (string day in days) { if (day == testDay) { return i; } i++; } return -1; } public int this[string day] { get { return GetDay(day); } } } class Program { static void Main(string[] args) { DayCollection week = new DayCollection(); Console.WriteLine(week["Fri"]); Console.WriteLine(week["Invalid Day"]); Console.ReadKey(); } } }
运行结果为:5,-1;
再例如:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication2 { class TempRecord { private float[] temps = new float[10]{56.2F,56.7F,56.5F,56.9F,58.8F, 61.3F,65.9F,62.1F,59.2F,57.5F}; System.DateTime date { get; set; } public int Length { get { return temps.Length; } } public float this[int index] { get { return temps[index]; } set { temps[index] = value; } } } class Program { static void Main(string[] args) { TempRecord temp = new TempRecord(); temp[3] = 58.3F; temp[5] = 60.1F; for (int i = 0; i < 10; i++) { if (i < temp.Length) { Console.WriteLine("元素{0}={1}", i, temp[i]); } else { Console.WriteLine("索引值{0}超出范围",i); } } Console.ReadKey(); } } }
事件
事件是C#中的一个高级概念,是操作发生时允许执行特定于应用程序的代码的机制,事件要么在相关联的操作发生前发生(事前事件)要么在操作发生后发生(事后事件)。
例如,当用户单击窗口中的按钮时,将引发一个事后事件,以允许执行特定于应用程序的方法。
类和对象可以通过事件向其他类或对象通知发生的相关事情。发送(或引发)事件的类称为“发行者”,接受(或处理)事件的类称为“订户”。在典型的C#Windows 窗体或web应用程序中,可以订阅由控件(如按钮和列表框)引发的事件。如在考场上老师说“开始考试”,学生就开始答卷,其中老师说的“开始答卷”是事件,“学生开始答卷”是这个事件引发的动作。老师是事件的发行者。学生是事件的订户。
定义和使用事件一般有下面几个步骤
1,在一个类中声明关于事件的委托。
public delegate void 事件类型名称(object serder,EventArgs e);
事件的类型名称建议用EventHandler结尾。如果想自定义事件的参数EventArgs,可以用EventArgs类派生自己的事件参数类,也可以没有参数。
2,在类中声明事件。使用步骤1的delegate做为事件的类型。
public event 事件类型名称 事件名称;
3,在类中需要引发事件的方法中,编写引发事件的方法。
事件名称(this,new EventArgs());或者
if(事件名称!=null) 事件名称(this,new EventArgs());
4,订阅事件,当事件发生时通知订户。
带有事件的类的实例.事件名称+=new 事件名称(事件处理方法名称);
5,编写事件处理方法
public void 事件处理方法名称(object sender ,EventArgs e)
{
要添加的代码
}
6,在适当的条件下触发事件,即需要调用步骤3中的引发事件的方法。
范例:事件的定义和使用
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication2 { public class Heater { private int temperature; public delegate void BoilHandler(int param); public event BoilHandler BoilEvent; public void BoilWater() { for (int i = 0; i <= 100; i++) { temperature = i; if (temperature > 96) { if (BoilEvent != null) { BoilEvent(temperature); } } } } } public class Alarm { public void MakeAlert(int param) { Console.WriteLine("Alarm:滴滴滴,水已经{0}度了", param); } } public class Display { public static void ShowMsg(int param) { Console.WriteLine("Display:水快烧开了,当前温度:{0}度",param); } } class Program { static void Main(string[] args) { Heater heater = new Heater(); Alarm alarm = new Alarm(); heater.BoilEvent += alarm.MakeAlert; heater.BoilEvent += Display.ShowMsg; heater.BoilWater(); Console.ReadKey(); } } }
运行结果为:
把Heater类不变,去掉Alarm类和Display类,使用匿名方法订阅事件
如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication2 { public class Heater { private int temperature; public delegate void BoilHandler(int param); public event BoilHandler BoilEvent; public void BoilWater() { for (int i = 0; i <= 100; i++) { temperature = i; if (temperature > 96) { if (BoilEvent != null) { BoilEvent(temperature); } } } } } class Program { static void Main(string[] args) { Heater heater = new Heater(); heater.BoilEvent += delegate(int param) { Console.WriteLine("Alarm:嘀嘀嘀,水已经{0}度了。", param); }; heater.BoilEvent += delegate(int param) { Console.WriteLine("Display:水烧开了,当前温度为:{0}度",param); }; heater.BoilWater(); Console.ReadKey(); } } }
运行结果与之前相同。