------- Windows Phone 7手机开发、.Net培训、期待与您交流! ------- 委托和事件 在C#开发中,有时需要实现这样的情况:只要新添加一个对象,就要执行一系列的方法。如果每次挨个调用,浪费时间,还使代码冗余。这时候可以使用委托。委托建立的是一个方法链条。设置好后,可以让一个对象依次去执行这个链条上的各个方法。它可以简化代码,提高代码效率,使代码容易维护。事件是一种特殊的委托,它在某些操作发生时自动地发出通知。 使用委托 委托是一个能够引用方法的对象,能够调用它所指向的方法。而且,在程序运行期间,同一个委托可以调用不同的方法,只要改变它引用的方法即可。所有委托类型的基类是System.Delegate类。System.Delegate类本身不是委托类型,而且不允许显式地直接从该类派生新的类型。 声明委托 委托同类一样,在使用之前需要声明。委托类型的声明将创建一个协定,该协定指定一个或多个方法的签名。委托是委托类型的实例,它可以引用静态方法或者实例方法。声明委托需要使用delegate关键字,委托的修饰符它包括new、public、protected、internal和private共5个关键字。其中,public、protected、internal和private修饰符控制委托的可访问性。 public修饰符:表示该委托是公开的,访问不受限制。 protected修饰符:表示该委托只能是本身委托访问。 internal修饰符:表示该委托只能是在当前应用程序中访问。 private修饰符:表示该委托只能是本身访问。 注意:只有在其他类型中声明委托时,才能够使用new修饰符。它表示所声明的委托会隐藏具有相同名称的继承成员。 声明名称为MyDelegate的委托MyDelegate委托的返回类型为int,方法参数为int i, int j。 public delegate int MyDelegate(int i,int j); //声明委托MyDelegate 注意:委托类型默认是从System.Delegate派生的类类型,它隐含为密封类型,因此不能从委托类型派生一个新的类型。 向委托注册方法 委托声明好了后,就要给委托添加方法列表,使得创建对象后可以依次执行各个方法。给委托添加方法列表即创建向委托注册方法。如果一个方法要注册到某一个委托中,那么该方法的签名必须与该委托的所指定的签名完全匹配。 匹配规则: 方法的返回类型必须和委托的返回类型相同。 方法的方法参数必须和委托的方法参数相同,参数的具体名称可以不相同。 声明一个名称为MyDelegate的委托。MyDelegate委托的返回类型为int,方法参数为int i, int j。 public delegate int MyDelegate (int i,int j); //声明委托MyDelegate 声明5个方法:F1、F2、F3、F4和F5,它们能否注册到MyDelegate委托的具体说明。 public void F1(int i,int j)方法:返回类型与MyDelegate委托不相同,不能注册到MyDelegate委托的方法列表中。 public void F2(int i)方法:返回类型与MyDelegate委托不相同,且方法参数也不相同,不能注册到MyDelegate委托的方法列表中。 public int F3(int i)方法:返回类型与MyDelegate委托相同,但是方法参数不相同,不能注册到MyDelegate委托的方法列表中。 public int F4(int i,int j)方法:返回类型与MyDelegate委托相同,且方法参数相同,能够注册到MyDelegate委托的方法列表中。 public int F5(int k,int l)方法:返回类型与MyDelegate委托相同,且方法参数相同(虽然参数的名称不相同),能够注册到MyDelegate委托的方法列表中。 public void F1(int i,int j){} //不能注册到MyDelegate委托的方法列表中 public void F2(int i){} //不能注册到MyDelegate委托的方法列表中 public int F3(int i){} //不能注册到MyDelegate委托的方法列表中 public int F4(int i,int j){} //能够注册到MyDelegate委托的方法列表中 public int F5(int k,int l){} //能够注册到MyDelegate委托的方法列表中 实例化委托 委托也是一个类,因此,委托需要实例化。委托实例化可以创建委托类型的实例,并向该实例注册方法列表。委托类型的实例的方法列表可以为静态方法、实例方法或者另外一个委托实例。 注意:委托实例化,它把静态方法、实例方法或者另外一个委托的名称作为该实例的方法参数进行传递。 声明一个委托和一个类,它们的名称分别为MyDelegate和Program。MyDelegate委托的返回类型为int,方法参数为int i。 Program类声明两个方法:F1(int i)和F2(int j)。其中,F1(int i)方法为实例方法,F2(int j)方法为静态方法。然后Program类创建MyDelegate委托的两个个实例:d1和d2。 其中,d1实例将注册Program类的的实例p的实例方法F1(int i),d2实例将注册Program类的静态方法F2(int j)。 delegate int MyDelegate( int i ); class Program { public int F1( int i ) // 声明一个实例方法 { Console.WriteLine(" 调用实例方法 F1(int i) "); return i; } public static int F2(int j) //声明静态方法 { Console.WtiteLine(" 调用静态方法 F2( int j ) "); return j; } static void Main(string[] args) { Program p = new Program(); MyDelegate d1 = new MyDelegate(p.F1); //创建d1实例 int i = d1(10); Console.WriteLine(" i = " + i ); MyDelegate d2 = new MyDelegate(Program.F2); //创建d2实例 int j = d2(20); Console.WriteLine(" j = " + j); Console.ReadLine(); } } 构建委托的方法列表 使用委托可以将多个方法绑定到同一个委托变量。当调用此变量时,可以依次调用所有绑定的方法。每个委托实例都必须包含其方法列表,方法列表可以包含一个或多个方法。委托实例除了在其实例化时注册方法之外,还可以通过“+”或“+=”运算符向该实例的方法列表中注册方法,通过“-”或“-=”运算符从该实例的方法列表中移除方法。 声明一个委托和一个类,它们的名称分别为MyDelegate和Program。MyDelegate委托的返回类型为int,方法参数为int i。Program类声明两个静态方法:F1(int i)和F2(int i)。然后创建MyDelegate委托的5个实例:d1、d2、d3、d4和d5。它们的具体说明如下: d1实例调用Program类的F1方法。 d2实例调用Program类的F2方法。 d3实例依次调用Program类的F1、F2方法。 d4实例依次调用Program类的F1、F2、F2、F1方法。 d5实例依次调用Program类的F1、F2、F1方法。 public delegate int MyDelegate ( int i ); public class Program { public static int F1 ( int i ) // 定义静态方法 F1 { Console.WriteLine(" 调用静态方法 F1 ( int i ) "); return i ; } public static int F2 ( int j ) // 定义静态方法 F2 { Console.WriteLine(" 调用静态方法 F2 ( int j ) "); return j ; } static void Main(string[] args) { MyDelegate d1 = new MyDelegate( Program.F1 ); //注册方法 F1 MyDelegate d2 = new MyDelegate( Program.F2 ); //注册方法 F2 MyDelegate d3 = d1 + d2 ; //给委托 d3 注册方法 MyDelegate d4 = d3 + d2 + d1 ; //给委托 d4 注册方法 MyDelegate d5 = d4 + d2 ; //给委托 d5 注册方法 int i1 = d1( 20 ); Console.WriteLine(" i1 = " + i1 ); int i2 = d2( 20 ); Console.WriteLine(" i2 = " + i2 ); int i3 = d3( 20 ); Console.WriteLine(" i3 = " + i3 ); int i4 = d4( 20 ); Console.WriteLine(" i4 = " + i4 ); int i5 = d5( 20 ); Console.WriteLine(" i5 = " + i5 ); Console.ReadLine(); } } d1和d2实例通过“+”运算符得到d3实例。d1、d2和d3实例通过“+”运算符得到d4实例。d5实例等于d4实例-d2实例,即表示从d4实例的方法列表的末端开始查找。如果该方法被包括在d2实例的方法列表中,则从d4实例的方法列表中移除该方法。 调用委托 委托是一个方法链条,因此,调用委托实例就相当于调用了该委托实例包含的所有方法。如果一个调用列表包含多个方法时,当该委托实例被调用时,它将按照调用列表中方法的注册顺序依次调用每一个方法。 声明一个委托和一个类,它们的名称分别为MyDelegate和Program。MyDelegate委托的返回类型为void,方法参数为int i。 Program类声明两个静态方法:F1(int i)和F2(int i)。 F1(int i)方法输出“Program.F1:”和i参数的值, F2(int i)方法输出“Program.F2:”和i参数的值。 Program类创建MyDelegate委托的5个实例:d1、d2、d3、d4和d5。 d1实例调用Program类的F1方法。 d2实例调用Program类的F2方法。 d3实例依次调用Program类的F1、F2方法。 d4实例依次调用Program类的F1、F2、F2、F1方法。 d5实例依次调用Program类的F1、F2、F1方法。 public delegate void MyDelegate ( int i ); public class Program { public static void F1( int i ) { Console.WriteLine(" Program.F1 " + i.ToString() ); } public static void F2 ( int i ) { Console.WriteLine(" Program.F2 " +i.ToString() ); } static void Main(sting[] args) { MyDelegate d1 = new MyDelegate(Program.F1); // 创建 d1 实例调用 Program 类的 F1 方法 MyDelegate d2 = new MyDelegate(Program.F2); // 创建 d2 实例调用 Program 类的 F2 方法 MyDelegate d3 = d1 + d2 ; // d3 实例调用了 Program 类的 F1, F2 方法 MyDelegate d4 = d3 + d2 + d1 ; // d4 实例调用了 Program 类的 F1, F2 , F2 , F1方法 MyDelegate d5 = d4 + d2 ; // d5 实例调用了 Program 类的 F1, F2 , F1方法 d1( 10 ) ; Console.WriteLine(); d2( 200 ); Console.WriteLine(); d3( 3000 ) ; Console.WriteLine(); d4( 40000 ) ; Console.WriteLine(); d5( 500000 ) ; Cnsole.WriteLine(); Console.ReadLine(); } } d1(10);”表达式调用了d1实例,并调用了F1方法。 d2(200);”表达式调用了d2实例,并调用了F2方法。 d3(3000);”表达式调用了d3实例,并依次调用了F1、F2方法。 d4(40000);”表达式调用了d4实例,并依次调用了F1、F2、F2、F1方法。 d5(500000);”表达式调用了d5实例,并依次调用了F1、F2、F1方法。 使用事件 事件是某些操作发生时自动地发出通知,就像水开了之后发出声音,人听到声音就去关掉电源。事件构建在委托的基础上,它是一种信号机制。程序员可以通过提供事件处理程序为相应的事件添加可执行代码。当事件触发时,将调用该事件事先定义的方法。 声明事件 事件同委托一样,使用之前也需要声明。事件是一种特殊类型的委托,它包含两个参数:指示事件源的“对象源”参数和封装事件的其他任何相关信息的e参数。其中,e参数的类型为System.EventArgs类型或从System.EventArgs类派生的类型。 声明事件一般包括以下两个步骤。 (1)声明事件的委托 声明一个名称为EventHandler的事件委托,它包含两个参数:sender和e。其中,sender参数表示事件源,e参数表示与该事件相关的信息。 public delegate void EventHandler(object sender, EventArgs e); (2)声明事件本身 在声明事件时,需要使用event关键字。 声明一个名称为Print的事件,它的类型为EventHandler。 public event EventHandler Print; //声明事件Print 注册事件 事件同委托一样,需给事件注册方法列表。一个事件声明之后,该事件的默认值为null。 如果希望该事件执行事先指定的操作,则首先向该事件注册方法列表(即委托的调用列表)。注册事件可以使用“+=”运算符。 使用“+=”运算符向Print事件注册一个名称为F(object sender, EventArgs e)的方法。 public event void EventHandle ( object sender , EventArgs e ); // 定义委托 class Program { public event EventHandle Print ; // 定义事件 public void F ( object sender , EventArgs e ) { Console.WriteLine(" 调用方法 F( ) "); } static void Main(string[] args) { Program p = new Program(); p.Print += new EventHandle( p.F ) // 给事件 Print 注册方方法 F() if ( p.Print != null ) { p.Print ( null , null ) ; // 调用事件 } Console.ReadLine(); } } 移除事件 除了注册事件之外,还可以移除事件。移除事件使用“-=”运算符。 使用“-=”运算符从Print事件的方法列表中移除一个名称为F1 (object sender, EventArgs e)的方法。 public delegate EventHandle ( object sender , EventArgs e ); class Program { public enevt EventHandle Print; public void F1 ( object sender , EventArgs e ) { Console.WriteLine(" 方法 F1 ( ) "); } public void F2 ( object sender , EventArgs e ) { Console.WriteLine(" 方法 F2 ( ) "); } static void Main(sting[] args) { Program p = new Program(); p.Print += new EventHandle ( p.F1 ); //添加方法 p.Print += new EventHandle ( p.F2 ); Console.WriteLine(" 事件中的方法列表: "); if ( p.Print != null ) { p.Print ( null , null ); } Console.WriteLine(); p.Print -= new EventHandle ( p.F1 ); // 移除方法 Console.WriteLine(" 移除 F1 之后: "); if ( p.Print != null ) { p.Print ( null , null ); } Console.ReadLine(); } } 调用事件 声明一个事件之后,如果没有向该事件注册方法,那么该事件的值为空(null)。因此,在调用事件时,往往需要检查该事件是否为空。 调用Print事件。在调用该事件之前,首先判断了该事件是否为空。只要当该事件不为空时,才调用该事件。调用Print事件的参数的值均为null。 public delegate void EventHandle ( object sender , EventArgs e ); // 创建一个委托 EventHandle class Program { public event EventHandle Print; // 定义事件 Print public void F1( object sender , EventArgs e ) // 定义方法 { Console.WriteLine(" 方法 F1 "); } static void Main(sting[] args) { Program p = new Program(); // 实例化类 p.Print += new EventHandle( p.F1 ); // 将 F1 方法添加到 Print 事件中去 if ( p.Print != null ) { p.Print( null , null ); // 调用事件 } Console.ReadLine(); } } ------- Windows Phone 7手机开发、.Net培训、期待与您交流! -------