C# 委托与事件

 委托,相当于函数指针,是引用类型,有多播功能

委托的声明    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 }
网络爬虫
原文地址:https://www.cnblogs.com/GoldenEllipsis/p/10349878.html