委托和事件复习
2007 - 09 - 05 18 : 51
一、委托
委托实际上就是C ++ 里面的函数指针,你可以让这个指针指向委托定义时所声名的那种类型的函数。举个例子:
public delegate void 连接数据库委托();
表示:声名一个委托类型,这个委托叫“连接数据库委托”,它所能指向的函数都是返回值为void型,没有参数的函数。比如:
private void 连接Oracle数据库();
private void 连接SqlServer数据库();
我们现在的程序里面要根据用户设定的数据库类型,自动连接数据库。
程序里面可以这么写:
连接数据库委托 委托实例 = null ;
switch (目标数据库类型)
{
case 数据库类型.Oracle数据库:
委托实例 += new 连接数据库委托(连接Oracle数据库);
break;
case 数据库类型.SqlServer数据库:
委托实例 += new 连接数据库委托(连接SqlServer数据库);
break;
}
委托实例(); // 运行委托所指向的函数
这里就能根据上面的switch来执行相应的连接数据库函数了。
委托是种类型,所以跟其他类型一样,可以当参数传递。
委托还有一个重要特性就是多播(Multicasting)
就是说执行一个委托实例的时候,可以同时执行一个以上的函数。
比如说我的程序要连接Oracle数据库,同时还要连接SqlServer数据库,可以这么写:
委托实例 += new 连接数据库委托(连接Oracle数据库);
委托实例 += new 连接数据库委托(连接SqlServer数据库);
委托实例(); // 运行委托所指向的函数
这样就同时执行了两个函数
二、委托例子的完整代码
// DelegateTest.cs
using System;
using System.Threading;
namespace ConsoleApp_CS
{
public class AppClass
{
public delegate void 连接数据库委托();
private static void 连接Oracle数据库()
{
Console.WriteLine("已经连接到Oracle数据库n");
}
private static void 连接SqlServer数据库()
{
Console.WriteLine("已经连接到连接SqlServer数据库数据库n");
}
public static void Main()
{
连接数据库委托 数据库连接;
数据库连接 = new 连接数据库委托(连接Oracle数据库);
Console.WriteLine("<<仅连接到Oracle数据库");
数据库连接(); //仅连接到Oracle数据库
数据库连接 = new 连接数据库委托(连接SqlServer数据库);
Console.WriteLine("<<仅连接到SqlServer数据库");
数据库连接(); //仅连接到SqlServer数据库
数据库连接 = null;
数据库连接 += new 连接数据库委托(连接Oracle数据库);
数据库连接 += new 连接数据库委托(连接SqlServer数据库);
Console.WriteLine("<<同时连接到两个数据库");
数据库连接();
Console.Read();
}
}
}
三、事件
可以这么理解:当某件事发生的时候,会有一个广播信号,告诉大家什么事情发生了。某些人可能不关心股票事件,有些人不关心其他国家发洪水事件。这样事件就需要订阅,你只订阅你感兴趣的事件。当事件发生时,那些订阅该事件的订阅者就会收到一个信号,告诉你这个事件发生了。你可以对这个事件不闻不问,这个跟没订阅该事件一样,有些人会对这个事件进行一些处理,比如:
公司饮水机在我旁边,我关心饮水机是否没水了,所以我订阅一个“饮水机没水了”这个事件。
公司饮水机.饮水机没水了 += new 公司饮水机.饮水机没水了委托(我.换水);
这样,当饮水机没水了事件触发时,我就被通知要换水,执行的是“我”这个实例的“换水”方法。
饮水机Class 看起来大概是这样的:
public class 饮水机
{
private int 水量 = 10;
public delegate void 饮水机没水了委托();
public event 饮水机没水了委托 饮水机没水了;
public void 出水(int 出水量)
{
Console.WriteLine("有人接水……");
水量 -= 出水量;
Console.WriteLine("桶里还剩{0}升水", 水量);
if(水量 == 0)
{
当饮水机没水了();
}
}
public void 当饮水机没水了()
{
if(饮水机没水了 != null)
{
Console.WriteLine("饮水机没水了,快来换水……");
饮水机没水了(); //触发这个事件
}
}
}
而公司员工Class 看起来大概是这样的:
public class 公司员工
{
public void 换水()
{
Console.WriteLine("我去换水,真累啊……");
}
}
Main函数里应该这样
饮水机 公司饮水机 = new 饮水机();
公司员工 我 = new 公司员工();
公司饮水机.饮水机没水了 += new 饮水机.饮水机没水了委托(我.换水);
for ( int i = 0 ; i < 10 ; i ++ )
{
公司饮水机.出水(1);
Thread.Sleep(1000);
}
Console.Read();
要注意的一点是:在“当饮水机没水了”函数内,应该判断“饮水机没水了”是否为null,否则就不要执行“饮水机没水了();”
四、事件例子的完整代码
// EventTest.cs
using System;
using System.Threading;
namespace ConsoleApp_CS
{
public class 饮水机
{
private int 水量 = 10;
public delegate void 饮水机没水了委托();
public event 饮水机没水了委托 饮水机没水了_事件;
public void 出水(int 出水量)
{
Console.WriteLine("有人接水……");
水量 -= 出水量;
Console.WriteLine("桶里还剩{0}升水", 水量);
if(水量 == 0)
{
当饮水机没水了();
}
}
public void 当饮水机没水了()
{
if(饮水机没水了_事件 != null)
{
Console.WriteLine("饮水机没水了,快来换水……");
饮水机没水了_事件(); //触发这个事件
}
}
}
public class 公司员工
{
public void 换水()
{
Console.WriteLine("我去换水,真累啊……");
}
}
public class AppClass
{
public static void Main()
{
饮水机 公司饮水机 = new 饮水机();
公司员工 我 = new 公司员工();
公司饮水机.饮水机没水了_事件 += new 饮水机.饮水机没水了委托(我.换水);
for(int i=0; i<10; i++)
{
公司饮水机.出水(1);
Thread.Sleep(1000);
}
Console.Read();
}
}
}
------------------------------------------------------------
1 .委派的实现过程。
首先来看一下委派,委派其实就是方法的传递,并不定义方法的实现。事件其实就是标准化了的委派,为了事件处理过程特制的、稍微专业化一点的组播委派(多点委派)。下面举一个例子,我觉得把委派的例子和事件的例子比较,会比较容易理解。
using System;
class Class1
{
delegate int MathOp(int i1,int i2);
static void Main(string[] args)
{
MathOp op1=new MathOp(Add);
MathOp op2=new MathOp(Multiply);
Console.WriteLine(op1(100,200));
Console.WriteLine(op2(100,200));
Console.ReadLine();
}
public static int Add(int i1,int i2) {
return i1+i2;
}
public static int Multiply(int i1,int i2)
{
return i1*i2;
}
}
首先代码定义了一个委托mathop,其签名匹配与两个函数add()和multiply()的签名(也就是其带的参数类型数量相同):
delegate int MathOp( int i1, int i2);
main()中代码首先使用新的委托类型声明一个变量,并且初始化委托变量.注意,声明时的参数只要使用委托传递的函数的函数名,而不加括号:
mathop op1 = new MathOp(Add);
(或为mathop op1 = new MathOp(Multiply);)
委托传递的函数的函数体:
public static int Add( int i1, int i2)
{
return i1+i2;
}
public static int Multiply( int i1, int i2)
{
return i1*i2;
}
然后把委托变量看作是一个函数名,将参数传递给函数。 Console.WriteLine(op1( 100 , 200 ));
console.writeline(op2( 100 , 200 ));
2 .事件的实现过程
using System;
class Class1
{
static void Main(string[] args)
{
Student s1=new Student();
Student s2=new Student();
s1.RegisterOK +=new Student.DelegateRegisterOkEvent(Student_RegisterOK);
s2.RegisterOK +=new Student.DelegateRegisterOkEvent(Student_RegisterOK);
s1.Register();
s2.Register();
Console.ReadLine();
}
static void Student_RegisterOK()
{
Console.WriteLine("Hello");
}
}
class Student
{
public delegate void DelegateRegisterOkEvent();
public event DelegateRegisterOkEvent RegisterOK;
public string Name;
public void Register()
{
Console.WriteLine("Register Method");
RegisterOK();
}
}
在student类中,先声明了委托delegateregisterokevent(),然后使用event和要使用的委托类型(前面定义的delegateregisterokevent委托类型)声明事件registerok(可以看作是委托的一个实例。):
public delegate void DelegateRegisterOkEvent();
public event DelegateRegisterOkEvent RegisterOK;
然后在main()函数中,实例化student类,然后s1.registerok事件委托给了student_registerok 方法。通过“ += ”(加等于)操作符非常容易地为.Net对象中的一个事件添加一个甚至多个响应方法;还可以通过非常简单的“ -= ”(减等于)操作符取消这些响应方法。
然后,当调用s1.register()时,事件s1.registerok发生。
2007 - 09 - 05 18 : 51
一、委托
委托实际上就是C ++ 里面的函数指针,你可以让这个指针指向委托定义时所声名的那种类型的函数。举个例子:
public delegate void 连接数据库委托();
表示:声名一个委托类型,这个委托叫“连接数据库委托”,它所能指向的函数都是返回值为void型,没有参数的函数。比如:
private void 连接Oracle数据库();
private void 连接SqlServer数据库();
我们现在的程序里面要根据用户设定的数据库类型,自动连接数据库。
程序里面可以这么写:
连接数据库委托 委托实例 = null ;
switch (目标数据库类型)
{
case 数据库类型.Oracle数据库:
委托实例 += new 连接数据库委托(连接Oracle数据库);
break;
case 数据库类型.SqlServer数据库:
委托实例 += new 连接数据库委托(连接SqlServer数据库);
break;
}
委托实例(); // 运行委托所指向的函数
这里就能根据上面的switch来执行相应的连接数据库函数了。
委托是种类型,所以跟其他类型一样,可以当参数传递。
委托还有一个重要特性就是多播(Multicasting)
就是说执行一个委托实例的时候,可以同时执行一个以上的函数。
比如说我的程序要连接Oracle数据库,同时还要连接SqlServer数据库,可以这么写:
委托实例 += new 连接数据库委托(连接Oracle数据库);
委托实例 += new 连接数据库委托(连接SqlServer数据库);
委托实例(); // 运行委托所指向的函数
这样就同时执行了两个函数
二、委托例子的完整代码
// DelegateTest.cs
using System;
using System.Threading;
namespace ConsoleApp_CS
{
public class AppClass
{
public delegate void 连接数据库委托();
private static void 连接Oracle数据库()
{
Console.WriteLine("已经连接到Oracle数据库n");
}
private static void 连接SqlServer数据库()
{
Console.WriteLine("已经连接到连接SqlServer数据库数据库n");
}
public static void Main()
{
连接数据库委托 数据库连接;
数据库连接 = new 连接数据库委托(连接Oracle数据库);
Console.WriteLine("<<仅连接到Oracle数据库");
数据库连接(); //仅连接到Oracle数据库
数据库连接 = new 连接数据库委托(连接SqlServer数据库);
Console.WriteLine("<<仅连接到SqlServer数据库");
数据库连接(); //仅连接到SqlServer数据库
数据库连接 = null;
数据库连接 += new 连接数据库委托(连接Oracle数据库);
数据库连接 += new 连接数据库委托(连接SqlServer数据库);
Console.WriteLine("<<同时连接到两个数据库");
数据库连接();
Console.Read();
}
}
}
三、事件
可以这么理解:当某件事发生的时候,会有一个广播信号,告诉大家什么事情发生了。某些人可能不关心股票事件,有些人不关心其他国家发洪水事件。这样事件就需要订阅,你只订阅你感兴趣的事件。当事件发生时,那些订阅该事件的订阅者就会收到一个信号,告诉你这个事件发生了。你可以对这个事件不闻不问,这个跟没订阅该事件一样,有些人会对这个事件进行一些处理,比如:
公司饮水机在我旁边,我关心饮水机是否没水了,所以我订阅一个“饮水机没水了”这个事件。
公司饮水机.饮水机没水了 += new 公司饮水机.饮水机没水了委托(我.换水);
这样,当饮水机没水了事件触发时,我就被通知要换水,执行的是“我”这个实例的“换水”方法。
饮水机Class 看起来大概是这样的:
public class 饮水机
{
private int 水量 = 10;
public delegate void 饮水机没水了委托();
public event 饮水机没水了委托 饮水机没水了;
public void 出水(int 出水量)
{
Console.WriteLine("有人接水……");
水量 -= 出水量;
Console.WriteLine("桶里还剩{0}升水", 水量);
if(水量 == 0)
{
当饮水机没水了();
}
}
public void 当饮水机没水了()
{
if(饮水机没水了 != null)
{
Console.WriteLine("饮水机没水了,快来换水……");
饮水机没水了(); //触发这个事件
}
}
}
而公司员工Class 看起来大概是这样的:
public class 公司员工
{
public void 换水()
{
Console.WriteLine("我去换水,真累啊……");
}
}
Main函数里应该这样
饮水机 公司饮水机 = new 饮水机();
公司员工 我 = new 公司员工();
公司饮水机.饮水机没水了 += new 饮水机.饮水机没水了委托(我.换水);
for ( int i = 0 ; i < 10 ; i ++ )
{
公司饮水机.出水(1);
Thread.Sleep(1000);
}
Console.Read();
要注意的一点是:在“当饮水机没水了”函数内,应该判断“饮水机没水了”是否为null,否则就不要执行“饮水机没水了();”
四、事件例子的完整代码
// EventTest.cs
using System;
using System.Threading;
namespace ConsoleApp_CS
{
public class 饮水机
{
private int 水量 = 10;
public delegate void 饮水机没水了委托();
public event 饮水机没水了委托 饮水机没水了_事件;
public void 出水(int 出水量)
{
Console.WriteLine("有人接水……");
水量 -= 出水量;
Console.WriteLine("桶里还剩{0}升水", 水量);
if(水量 == 0)
{
当饮水机没水了();
}
}
public void 当饮水机没水了()
{
if(饮水机没水了_事件 != null)
{
Console.WriteLine("饮水机没水了,快来换水……");
饮水机没水了_事件(); //触发这个事件
}
}
}
public class 公司员工
{
public void 换水()
{
Console.WriteLine("我去换水,真累啊……");
}
}
public class AppClass
{
public static void Main()
{
饮水机 公司饮水机 = new 饮水机();
公司员工 我 = new 公司员工();
公司饮水机.饮水机没水了_事件 += new 饮水机.饮水机没水了委托(我.换水);
for(int i=0; i<10; i++)
{
公司饮水机.出水(1);
Thread.Sleep(1000);
}
Console.Read();
}
}
}
------------------------------------------------------------
1 .委派的实现过程。
首先来看一下委派,委派其实就是方法的传递,并不定义方法的实现。事件其实就是标准化了的委派,为了事件处理过程特制的、稍微专业化一点的组播委派(多点委派)。下面举一个例子,我觉得把委派的例子和事件的例子比较,会比较容易理解。
using System;
class Class1
{
delegate int MathOp(int i1,int i2);
static void Main(string[] args)
{
MathOp op1=new MathOp(Add);
MathOp op2=new MathOp(Multiply);
Console.WriteLine(op1(100,200));
Console.WriteLine(op2(100,200));
Console.ReadLine();
}
public static int Add(int i1,int i2) {
return i1+i2;
}
public static int Multiply(int i1,int i2)
{
return i1*i2;
}
}
首先代码定义了一个委托mathop,其签名匹配与两个函数add()和multiply()的签名(也就是其带的参数类型数量相同):
delegate int MathOp( int i1, int i2);
main()中代码首先使用新的委托类型声明一个变量,并且初始化委托变量.注意,声明时的参数只要使用委托传递的函数的函数名,而不加括号:
mathop op1 = new MathOp(Add);
(或为mathop op1 = new MathOp(Multiply);)
委托传递的函数的函数体:
public static int Add( int i1, int i2)
{
return i1+i2;
}
public static int Multiply( int i1, int i2)
{
return i1*i2;
}
然后把委托变量看作是一个函数名,将参数传递给函数。 Console.WriteLine(op1( 100 , 200 ));
console.writeline(op2( 100 , 200 ));
2 .事件的实现过程
using System;
class Class1
{
static void Main(string[] args)
{
Student s1=new Student();
Student s2=new Student();
s1.RegisterOK +=new Student.DelegateRegisterOkEvent(Student_RegisterOK);
s2.RegisterOK +=new Student.DelegateRegisterOkEvent(Student_RegisterOK);
s1.Register();
s2.Register();
Console.ReadLine();
}
static void Student_RegisterOK()
{
Console.WriteLine("Hello");
}
}
class Student
{
public delegate void DelegateRegisterOkEvent();
public event DelegateRegisterOkEvent RegisterOK;
public string Name;
public void Register()
{
Console.WriteLine("Register Method");
RegisterOK();
}
}
在student类中,先声明了委托delegateregisterokevent(),然后使用event和要使用的委托类型(前面定义的delegateregisterokevent委托类型)声明事件registerok(可以看作是委托的一个实例。):
public delegate void DelegateRegisterOkEvent();
public event DelegateRegisterOkEvent RegisterOK;
然后在main()函数中,实例化student类,然后s1.registerok事件委托给了student_registerok 方法。通过“ += ”(加等于)操作符非常容易地为.Net对象中的一个事件添加一个甚至多个响应方法;还可以通过非常简单的“ -= ”(减等于)操作符取消这些响应方法。
然后,当调用s1.register()时,事件s1.registerok发生。