委托,相当于函数指针,是引用类型,有多播功能
委托的声明 public delegate double MyDelegate ( double x );
委托就是函数原型,起一个名字。
委托的实例化 MyDelegated d2 = new MyDelegate( obj.myMethod );
委托变量,是某个对象的方法或者某个类的方法
委托的调用 委托变量名(参数列表 ) d2(8.9)
委托的合并 多播MultiCastDelegate
一个委托实例中可以“包含”多个函数
调用委托,就是调用其中多个函数
多个函数间的先后顺序是没有意义的
返回值也就没有太多意义
运算符 + - += -=
动态地增减其中的函数
提高了程序的灵活性
1 using System; 2 3 public delegate void Action(); 4 5 class Program 6 { 7 public static void Main(string[] args) 8 { 9 //实例化对象 10 Mom mom = new Mom(); 11 Dad dad = new Dad(); 12 Child child = new Child(); 13 14 //将爸爸和孩子的Eat方法注册到妈妈的Eat事件 15 //订阅妈妈开饭的消息 16 mom.Eat += dad.Eat; 17 mom.Eat += child.Eat; 18 19 //调用妈妈的Cook事件 20 mom.Cook(); 21 22 Console.Write("Press any key to continue . . . "); 23 Console.ReadKey(true); 24 } 25 } 26 27 public class Mom 28 { 29 //定义Eat事件,用于发布吃饭消息 30 public event Action Eat; 31 32 public void Cook() 33 { 34 Console.WriteLine("妈妈 : 饭好了"); 35 //饭好了,发布吃饭消息!!! 36 Eat(); 37 //Eat?.Invoke(); 38 //(Eat).Invoke(); 39 } 40 } 41 42 public class Dad 43 { 44 public void Eat() 45 { 46 //爸爸去吃饭 47 Console.WriteLine("爸爸 : 吃饭了。"); 48 } 49 } 50 51 public class Child 52 { 53 public void Eat() 54 { 55 //熊孩子LOL呢,打完再吃 56 Console.WriteLine("孩子 : 打完这局再吃。"); 57 } 58 }
事件,相当于回调函数,是一种消息机制,事件源调用事件,别的类注册事件,事件的类型是一个委托
事件实质上就是一个委托,是受限制的委托,只能在类内部定义,以类对象调用类方法的形式,激发。
事件的声明
public event 委托名 事件名;
事件的注册与移除
事件名 += 或 -=
在事件所在类的外面,只能用以上两个运算符
事件的发生(激发)
事件名(参数列表)
相当于回调所注册的函数
1 /*事件与委托*/ 2 3 using System; 4 delegate void Handler(); 5 6 class Incrementer//发布者 7 { 8 public event Handler CountedADozen; //定义CountedADozen事件 9 public void DoCount()//触发事件的方法 10 { 11 for (int i = 1; i < 50; i++) 12 {//每增加12个计数就触发事件一次,私有委托为空就不执行 13 if (i % 12 == 0 && CountedADozen != null) 14 { 15 CountedADozen(); 16 } 17 } 18 } 19 } 20 21 22 class Dozens 23 { 24 public Dozens(Incrementer incrementer)//在发布者私有委托里增加方法 25 { 26 incrementer.CountedADozen += IncrementDozensCount; 27 } 28 29 void IncrementDozensCount()//事件成员被触发时要调用的方法 30 { 31 Console.WriteLine("Dozens"); 32 } 33 } 34 35 36 class SomeOtherClass 37 { 38 public SomeOtherClass(Incrementer incrementer) 39 { 40 incrementer.CountedADozen += DoSomething;//在发布者私有委托里增加方法 41 } 42 43 public void DoSomething()//事件成员被触发时要调用的方法 44 { 45 Console.WriteLine("SomeOtherClass"); 46 } 47 } 48 49 50 class Program 51 { 52 static void Main() 53 { 54 Incrementer incrementer = new Incrementer(); 55 Dozens dozensCounter = new Dozens(incrementer); 56 SomeOtherClass other = new SomeOtherClass(incrementer); 57 58 incrementer.DoCount(); 59 60 Console.Write("Press any key to continue . . . "); 61 Console.ReadLine(); 62 } 63 }
定义及使用事件的6步曲
公用的
声明事件参数类: class xxxEventArgs{}
声明委托: delegate void xxxEventHandler(obj, args)
在一个类中
定义事件: public event 类型 名称
发生事件: 在这个类的方法中,事件名(参数)
在别的类中
定义一个方法: void 方法名(obj, args)
注册事件 : xxx.事件 += new 委托(方法名)
(可以使用匿名函数或lamda表达式进行注册)
1 this.button1.Click += new System.EventHandler(this.button1_Click); 2 private void button1_Click(object sender, EventArgs e) 3 { 4 this.label1.Text = DateTime.Now.ToString(); 5 }
1 using System; 2 using System.Collections.Generic; 3 using System.Text; 4 5 namespace UsingEvent 6 { //声明一个委托 7 public delegate void ClickEventHandler(object sender, EventArgs e); 8 9 public class MyButton //创建MyBottom 10 { 11 public event ClickEventHandler ClickEvent;//声明一个事件 12 13 public void Click() //单击MyButton 14 { 15 if (ClickEvent != null) 16 { 17 Console.WriteLine("MyButton: 我被单击了"); 18 ClickEvent(this, null); //抛出事件,给所有响应者 19 } 20 } 21 } 22 23 public class MyForm 24 { 25 public MyButton myButton = new MyButton(); 26 27 public MyForm() 28 { 29 //注册事件,当myButton被单击的时候就会调用响应的处理函数 30 myButton.ClickEvent += new ClickEventHandler(OnClickEvent); 31 /*myButton.ClickEvent += OnClickEvent; */ 32 } 33 34 //事件处理函数 35 void OnClickEvent(object sender, EventArgs e) 36 { 37 Console.WriteLine("MyForm: 我知道你被单击了!"); 38 } 39 } 40 41 class Program 42 { 43 static void Main(string[] args) 44 { 45 MyForm form = new MyForm();//生成一个MyForm 46 form.myButton.Click();//单击MyForm中的鼠标,效果就出来了 47 Console.ReadLine(); 48 } 49 } 50 }
事件与委托的关系
事件有点像委托类型的实例
事件一定有相关的委托类型
与委托实例一样,事件也“包含”多个函数
事件的运算受更多限制(在类外只能用+=或-=)
事件比委托实例更复杂
可以定义事件存取器
修饰符 event 委托类型名 事件名
{
add { e += value; }
remove { e -= value; }
}
1 using System; 2 3 /* 声明委托 4 DownloadStartHandler 5 DownloadEndHandler 6 DownloadingHandler */ 7 public delegate void DownloadStartHandler(object sender, DownloadStartEventArgs e); 8 public delegate void DownloadEndHandler(object sender, DownloadEndEventArgs e); 9 public delegate void DownloadingHandler(object sender, DownloadingEventArgs e); 10 11 //DownloadStart事件参数类 12 public class DownloadStartEventArgs 13 { 14 public string Url{ get{ return _url;} set{ _url=value;} } 15 private string _url; 16 17 public DownloadStartEventArgs( string url ){ this._url = url; } 18 } 19 20 //DownloadEnd事件参数类 21 public class DownloadEndEventArgs 22 { 23 public string Url{ get{ return _url;} set{ _url=value;} } 24 private string _url; 25 26 public long ByteCount { get { return _byteCount; } set{ _byteCount=value;} } 27 private long _byteCount; 28 29 public DownloadEndEventArgs( string url, long size ){ this._url = url; this._byteCount=size; } 30 } 31 32 //Downloading事件参数类 33 public class DownloadingEventArgs 34 { 35 //网址属性 36 public string Url{ get{ return _url;} set{ _url=value;} } 37 //网址字段 38 private string _url; 39 40 //下载比例属性 41 public double Percent { get { return _percent; } set{ _percent=value;} } 42 //网址数据下载比例字段 43 private double _percent; 44 45 //构造函数 46 public DownloadingEventArgs( string url, double percent ){ this._url = url; this._percent=percent; } 47 } 48 49 50 public class Crawler 51 { 52 //事件 53 public event DownloadStartHandler DownloadStart; 54 public event DownloadEndHandler DownloadEnd; 55 public event DownloadingHandler Downloading; 56 57 //属性 58 public string Name { get{return name;} set{ name=value;} } 59 //字段 60 private string name; 61 private string site; 62 63 public Crawler( string name, string site ) 64 { 65 this.name = name; 66 this.site = site; 67 } 68 69 //事件触发方法 70 public void Craw() 71 { 72 while( true ) 73 { 74 //获取下一个网址 75 string url = GetNextUrl(); 76 if( url == null ) break; 77 78 //获取网址数据大小 79 long size = GetSizeOfUrl( url ); 80 81 //DownloadStart事件是否注册 82 if( DownloadStart != null ) 83 { 84 DownloadStart( this, new DownloadStartEventArgs(url)); 85 } 86 87 //模拟下载, 间隔100毫秒,下载1024的数据(+1024) 88 for( long i=0; i<size+1024; i+=1024 ) 89 { 90 //间隔100毫秒 91 System.Threading.Thread.Sleep( 100 ); 92 93 //计算下载比例 94 double percent = (int)(i*100.0/size); 95 if( percent>100) percent=100; 96 97 //Downloading事件是否注册 98 if( Downloading != null ) 99 { 100 //事件发生,传事件参数(Crawler类对象, DownloadingEventArgs参数类对象 ) 101 /* DownloadingEventArgs参数类对象参数 102 (Crawler类方法GetNextUrl获取的url, 103 Crawler类方法GetSizeOfUrl获取的url的数据大小,计算的下载比例percent)*/ 104 Downloading( this, new DownloadingEventArgs(url, percent)); 105 } 106 } 107 108 //DownloadEnd事件是否注册 109 if( DownloadEnd != null ) 110 { 111 //DownloadEnd事件发生,调用ShowEnd 112 DownloadEnd( this, new DownloadEndEventArgs(url, size)); 113 } 114 } 115 } 116 117 //获取下一个网址 118 private string GetNextUrl() 119 { 120 //模拟获取网址,随机产生网址编号,对字段site进行加工 121 int a = rnd.Next(10); 122 if( a == 0 ) return null; 123 return site + "/Page" + a + ".htm"; 124 } 125 126 //获取网址数据大小 127 private long GetSizeOfUrl( string url) 128 { 129 //模拟网址数据大小, 随机产生网址数据大小 130 return rnd.Next(3000 * url.Length); 131 } 132 133 //字段 134 private Random rnd = new Random(); 135 } 136 137 class Test 138 { 139 static void Main() 140 { 141 Crawler crawler = new Crawler("Crawer101", "http://www.pku.edu.cn"); 142 143 //注册事件 144 crawler.DownloadStart += new DownloadStartHandler( ShowStart ); 145 crawler.DownloadEnd += new DownloadEndHandler( ShowEnd ); 146 crawler.Downloading += new DownloadingHandler( ShowPercent ); 147 148 //触发事件 149 crawler.Craw(); 150 151 Console.ReadKey(); 152 } 153 154 static void ShowStart(object sender, DownloadStartEventArgs e){ 155 Console.WriteLine( (sender as Crawler).Name + "开始下载" + e.Url ); 156 } 157 158 static void ShowEnd(object sender, DownloadEndEventArgs e){ 159 Console.WriteLine( " 下载" + e.Url + "结束,其下载" + e.ByteCount + "字节" ); 160 } 161 162 static void ShowPercent(object sender, DownloadingEventArgs e){ 163 //DownloadingEventArgs参数类对象, e的Url属性 164 Console.Write( " 下载" + e.Url + "......." + e.Percent + "%" ); 165 } 166 }