黑马程序员_委托和事件
2013-11-21 16:16
218 查看
------- Windows Phone 7手机开发、.Net培训、期待与您交流! -------
委托和事件
在C#开发中,有时需要实现这样的情况:只要新添加一个对象,就要执行一系列的方法。如果每次挨个调用,浪费时间,还使代码冗余。这时候可以使用委托。委托建立的是一个方法链条。设置好后,可以让一个对象依次去执行这个链条上的各个方法。它可以简化代码,提高代码效率,使代码容易维护。事件是一种特殊的委托,它在某些操作发生时自动地发出通知。
使用委托
委托是一个能够引用方法的对象,能够调用它所指向的方法。而且,在程序运行期间,同一个委托可以调用不同的方法,只要改变它引用的方法即可。所有委托类型的基类是System.Delegate类。System.Delegate类本身不是委托类型,而且不允许显式地直接从该类派生新的类型。
声明委托
委托同类一样,在使用之前需要声明。委托类型的声明
4000
将创建一个协定,该协定指定一个或多个方法的签名。委托是委托类型的实例,它可以引用静态方法或者实例方法。声明委托需要使用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.Prin
a6b4
t += 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培训、期待与您交流! -------
相关文章推荐
- 黑马程序员_java编程基础第4天数组 二维数组
- 如何成为一名优秀的C程序员
- Java程序员应该了解的10个面向对象设计原则
- 美国有多少辆汽车? 05年毕业生经典面试题
- 黑马程序员:交通灯管理系统分析及代码实现
- 面试智力题(含答案)
- 黑马程序员_毕向东_Java基础视频教程学习笔记(二十二)
- 赞同博文“《REWORK》启示录 发出你的心声——程序员与身体”中关于健康的几个观点
- 程序员生活类-减肥篇
- 适用于Java程序员的通信顺序进程
- 黑马程序员:银行业务调度系统分析及代码实现
- 面试题:二叉树的层次遍历,包括定制树的建立
- 从程序员到CTO的Java技术路线
- 适用于Java程序员的通信顺序进程
- 程序员必看的十大电影
- “你最喜欢的程序员漫画”精选
- 从程序员到CTO的Java技术路线图 (转自安卓巴士)
- 黑马程序员_毕向东_Java基础视频教程学习笔记(二十一)
- 来个面试题:将1002格式转成一千零二
- 现在的全能程序员都是修炼出来的