[转发]C#深切剖析委托与事件

图片 1

事例1, 先把 int x 设置 一千,通过 Action 把表明式定义为 x=x+500
,最后经过 Invoke 激发委托。

[转载]C#深切剖析委托与事件,

初稿出处:

小编:风尘浪子

初稿链接:

同类链接:

引言

本篇小说将为您介绍一下 Delegate 的施用方法,逐步揭示 C#
当中事件(Event)的来由,它能使拍卖委托项目标历程变得进一步简约。
还将为你表达委托的协变与逆变,以及怎么着运用 Delegate 使
Observer(观看者)情势的选取变得特别简明。
在事件的介绍上,会讲述事件的使用方法,并以ASP.NET的用户控件为例子,介绍一下自定义事件的采纳。
提及底1节,将介绍Predicate<T>、Action<T>、Func<T,TResult>多种泛型委托的行使和Lambda的进化进度与其行使办法。
因为日子仓促,文中有荒唐的地点敬请点评。

 

目录

一、委托项指标原故

二、建设构造法委员会委员托类

三、委托行使方法

肆、长远解析事件

五、Lambda 表达式

 

一、委托项目标原委

回想在动用C语言的时代,整个项目中都充满着针指的人影,那时候流行使用函数指针来创设回调函数,使用回调能够把函数回调给程序中的另一个函数。但函数指针只是简短地把地点指向另一个函数,并不可能传递别的附加音讯。
在.NET中,在大好多时刻里都未曾指针的人影,因为指针被查封在内部函数在那之中。但是回调函数却依然留存,它是以信托的法子来产生的。委托能够被视为两个更加尖端的指针,它不仅仅能把地址指向另一个函数,而且还能传递参数,重回值等五个消息。系统还为委托对象自动生成了联合、异步的调用格局,开拓人员使用
BeginInvoke、EndInvoke 方法就能够屏弃 Thread 而直接运用多线程调用 。

重回目录

 

二、营造法委员会委员托类

动用delegate就足以一向建设构造任何名称的委托项目,当举行系统编写翻译时,系统就能自动生成此类型。您能够应用delegate
void MyDelegate()
情势创设2个委托类,并利用ILDASM.exe阅览其成员。由ILDASM.exe
中得以见到,它一连了System.MulticastDelegate类,并自动生成BeginInvoke、EndInvoke、Invoke
等八个常用艺术。

图片 2

Invoke
方法是用以共同调用委托对象的附和措施,而BeginInvoke、EndInvoke是用于以异步方式调用对应措施的。
对此异步调用的行使办法,能够参照:C#归咎揭秘——细说八线程

图片 3

1      public class MyDelegate:MulticastDelegate
2      {
3          //同步调用委托方法
4          public virtual void Invoke();
5          //异步调用委托方法
6          public virtual IAsyncResult BeginInvoke(AsyncCallback callback,object state);
7          public virtual void EndInvoke(IAsyncResult result);
8      }

图片 4

MulticastDelegate是System.Delegate的子类,它是二个独特类,编写翻译器和其它工具得以从此类派生,但是自定义类不能够显式地从此类实行派生。它帮助多路广播委托,并具有2个含有链接的嘱托列表,在调用多路广播委托时,系统将安份守己调用列表中的委托出现顺序来1只调用这么些委托。

MulticastDelegate具有五个常用属性:Method、Target。当中Method
用于获取委托所表示的不2诀要Target 用于获取当前调用的类实例。

MulticastDelegate有以下多少个常用艺术:

方法名称 说明
 Clone   创建委托的浅表副本。
 GetInvocationList   按照调用顺序返回此多路广播委托的调用列表。
 GetMethodImpl   返回由当前的 MulticastDelegate 表示的静态方法。
 GetObjectData   用序列化该实例所需的所有数据填充 SerializationInfo 对象。
 MemberwiseClone   创建当前 Object 的浅表副本。
 RemoveImpl   调用列表中移除与指定委托相等的元素

MulticastDelegate与Delegate给委托对象营造了强劲的协理,上边向各位详细介绍一下信托的应用办法。

重回目录

 

3、委托行使形式

三.一 轻便的寄托

当创建法委员会委员托对象时,委托的参数类型必须与信托方法相对应。只要向创建委托对象的构造函数中输入方法名称example.Method,委托就能直接绑定此方式。使用myDelegate.Invoke(string
message),就会显式调用委托方法。但在骨子里的操作中,我们不要用到 Invoke
方法,而只要直接使用myDelegate(string message),就能够调用委托方法。

图片 5

 1     class Program
 2     {
 3         delegate void MyDelegate(string message);
 4 
 5         public class Example
 6         {
 7             public void Method(string message)
 8             {
 9                 MessageBox.Show(message);
10             }
11         }
12 
13         static void Main(string[] args)
14         {
15             Example example=new Example();
16             MyDelegate myDelegate=new MyDelegate(example.Method);
17             myDelegate("Hello World");
18             Console.ReadKey();
19         }
20     }

图片 6

 

3.二 带重临值的信托

当建设构造法委员会委员托对象时,委托的重回值必须与寄托方法相对应。使用上面包车型客车例证,方法将赶回
“Hello Leslie” 。

图片 7

 1     class Program
 2     {
 3         delegate string MyDelegate(string message);
 4 
 5         public class Example
 6         {
 7             public string Method(string name)
 8             {
 9                 return "Hello " + name;
10             }
11         }
12 
13         static void Main(string[] args)
14         {
15             Example example=new Example();
16             //绑定委托方法
17             MyDelegate myDelegate=new MyDelegate(example.Method);
18             //调用委托,获取返回值
19             string message = myDelegate("Leslie");
20             Console.WriteLine(message);
21             Console.ReadKey();
22         }
23     }

图片 8

 

叁.三 多路广播委托

在第一节前已经提过,委托类承接于MulticastDelegate,那使委托对象援助多路广播,即委托对象可以绑定多少个格局。当输入参数后,每种方法会按梯次进行迭代管理,并重临最终五个办法的持筹握算结果。
下边包车型的士事例中,Price 类中有三个总计办法,Ordinary
按一般的玖.5折总计,Favourable 按巨惠价 八.5折计算。委托同时绑定了这三个方法,在输入参数拾0从此,Ordinary、Favourable这三个法子将按梯次迭代实践下去,最终回到
Favourable 方法的估算结果 八五。

图片 9

 1         delegate double MyDelegate(double message);
 2 
 3         public class Price
 4         {
 5             public double Ordinary(double price)
 6             {
 7                 double price1 = 0.95 * price;
 8                 Console.WriteLine("Ordinary Price : "+price1);
 9                 return price1;
10             }
11 
12             public double Favourable(double price)
13             {
14                 double price1 = 0.85 * price;
15                 Console.WriteLine("Favourable Price : " + price1);
16                 return price1;
17             }
18 
19             static void Main(string[] args)
20             {
21                 Price price = new Price();
22                 //绑定Ordinary方法
23                 MyDelegate myDelegate = new MyDelegate(price.Ordinary);
24                 //绑定Favourable方法
25                 myDelegate += new MyDelegate(price.Favourable);
26                 //调用委托
27                 Console.WriteLine("Current Price : " + myDelegate(100));
28                 Console.ReadKey();
29             }
30         }

图片 10

运维结果

图片 11

3.4 浅谈Observer模式

回想一下回顾的 Observer
情势,它应用壹对多的法门,能够让七个观看者同时关切同三个事物,并作出区别的响应。
比方下边的例子,Manager的底薪为主导报酬的1.5倍,Assistant的底薪为主干薪水的一.二倍。WageManager类的RegisterWorker方法与RemoveWorker方法能够用来注册和撤消阅览者,最后实施Execute方法能够对多个已登记的观望者同时输入参数。

 

图片 12

 

图片 13

 1     public class WageManager
 2     {
 3         IList<Worker> workerList = new List<Worker>();
 4         
 5         public void RegisterWorker(Worker worker)
 6         {
 7             workerList.Add(worker);
 8         }
 9 
10         public void RemoveWorker(Worker worker)
11         {
12             workerList.Remove(worker);
13         }
14 
15         public void Excute(double basicWages)
16         {
17             if (workerList.Count != 0)
18                 foreach (var worker in workerList)
19                     worker.GetWages(basicWages);
20         }
21 
22         static void Main(string[] args)
23         {
24             WageManager wageManager = new WageManager();
25             //注册观察者
26             wageManager.RegisterWorker(new Manager());
27             wageManager.RegisterWorker(new Assistant());
28             //同时输入底薪3000元,分别进行计算
29             wageManager.Excute(3000);
30 
31             Console.ReadKey();
32         }
33     }
34 
35     public abstract class Worker
36     {
37         public abstract double GetWages(double basicWages);
38     }
39 
40     public class Manager:Worker
41     {
42          //Manager实际工资为底薪1.5倍
43         public override double GetWages(double basicWages)
44         {
45             double totalWages = 1.5 * basicWages;
46             Console.WriteLine("Manager's wages is " + totalWages);
47             return totalWages;
48         }
49     }
50 
51     public class Assistant : Worker
52     {
53         //Assistant实际工资为底薪的1.2倍
54         public override double GetWages(double basicWages)
55         {
56             double totalWages = 1.2 * basicWages;
57             Console.WriteLine("Assistant's wages is " + totalWages);
58             return totalWages;
59         }
60     }

图片 14

运转结果

图片 15

 

支出 Observer
情势时借助委托,能够更进一步简化开拓的进度。由于委托对象扶助多路广播,所以能够把Worker类省略。在WageManager类中国建工业总群集团立了3个寄托对象wageHandler,通过Attach与Detach方法能够分别加入或撤除委托。借使观看者想对事物举办监测,只须求投入2个寄托对象就能够。记得在第一节曾经提过,委托的GetInvodationList方法能得到多路广播委托列表,在Execute方法中,便是通过去多路广播委托列表去看清所绑定的委托数量是不是为0。

图片 16

 1         public delegate double Handler(double basicWages);
 2  
 3          public class Manager
 4          {
 5              public double GetWages(double basicWages)
 6              {
 7                  double totalWages=1.5 * basicWages;
 8                  Console.WriteLine("Manager's wages is : " + totalWages);
 9                  return totalWages;
10              }
11          }
12  
13          public class Assistant
14          {
15              public double GetWages(double basicWages)
16              {
17                  double totalWages = 1.2 * basicWages;
18                  Console.WriteLine("Assistant's wages is : " + totalWages);
19                  return totalWages;
20              }
21          }
22  
23          public class WageManager
24          {
25              private Handler wageHandler;
26  
27              //加入观察者
28              public void Attach(Handler wageHandler1)
29              {
30                  wageHandler += wageHandler1;
31              }
32  
33              //删除观察者
34              public void Detach(Handler wageHandler1)
35              {
36                  wageHandler -= wageHandler1;
37              }
38  
39              //通过GetInvodationList方法获取多路广播委托列表,如果观察者数量大于0即执行方法
40              public void Execute(double basicWages)
41              {
42                  if (wageHandler!=null)
43                     if(wageHandler.GetInvocationList().Count() != 0)
44                         wageHandler(basicWages);
45              }
46  
47              static void Main(string[] args)
48              {
49                  WageManager wageManager = new WageManager();
50                  //加入Manager观察者
51                  Manager manager = new Manager();
52                  Handler managerHandler = new Handler(manager.GetWages);
53                  wageManager.Attach(managerHandler);
54  
55                  //加入Assistant观察者
56                  Assistant assistant = new Assistant();
57                  Handler assistantHandler = new Handler(assistant.GetWages);
58                  wageManager.Attach(assistantHandler);
59  
60                  //同时加入底薪3000元,分别进行计算
61                  wageManager.Execute(3000);
62                  Console.ReadKey();
63              }
64          }

图片 17

最后运转结果与地方的例证同样。

 

3.伍 委托的协变与逆变

在 Framework 二.0
出现在此之前,委托协变那些概念还尚未现身。此时因为委托是平安项目,它们不遵从继承的底蕴规则。即会那上边包车型客车情状:Manager
尽管是 Worker 的子类,但 GetWorkerHander 委托无法一直绑定 GetManager
方法,因为在委托当中它们的回到值 Manager 与 Worker
被视为完全毫无干系的五个品类。

图片 18

 1      public class Worker
 2      {.......}
 3      public class Manager:Worker
 4      {.......}
 5  
 6       class Program
 7      {
 8          public delegate Worker GetWorkerHandler(int id);
 9          public delegate Manager GetManagerHandler(int id);
10  
11          public static Worker GetWorker(int id)
12          {
13              Worker worker = new Worker();
14              ..............
15              return worker;
16          }
17  
18          public static Manager GetManager(int id)
19          {
20              Manager manager = new Manager();
21              ..............
22              return manager;
23          }
24  
25          static void Main(string[] args)
26          {
27              GetWorkerHandler workerHandler = new GetWorkerHandler(GetWorker);
28              var worker=workerHandler(1);
29  
30              GetManagerHandler managerHandler = new GetManagerHandler(GetManager);
31              var manager = managerHandler(2);
32              Console.ReadKey();
33          }
34      }

图片 19

从今Framework 二.0
面试之后,委托协变的概念就现身,此时委托能够根据守旧的承接规则实行调换。即
GetWorkerHandler 委托能够一贯绑定 GetManager 方法。

图片 20

 1      public class Worker
 2      {.......}
 3      public class Manager:Worker
 4      {.......}
 5  
 6       class Program
 7      {
 8          public delegate Worker GetWorkerHandler(int id);
 9          //在 Framework2.0 以上,委托 GetWorkerHandler 可绑定 GetWorker 与 GetManager 两个方法
10  
11          public static Worker GetWorker(int id)
12          {
13              Worker worker = new Worker();
14              return worker;
15          }
16  
17          public static Manager GetManager(int id)
18          {
19              Manager manager = new Manager();
20              return manager;
21          }
22  
23         static void Main(string[] args)
24         {
25             GetWorkerHandler workerHandler = new GetWorkerHandler(GetWorker);
26             Worker worker=workerHandler(1);
27             GetWorkerHandler managerHandler = new GetWorkerHandler(GetManager);
28             Manager manager = managerHandler(2) as Manager;
29             Console.ReadKey();
30         }
31      }

图片 21

委托逆变,是指委托方法的参数同样能够接收 “承袭”
那么些古板规则。像下边包车型大巴事例,以 object 为参数的嘱托,能够承受任何 object
子类的指标作为参数。最后能够在拍卖措施中采取 is
对输入数据的品种进行剖断,分别管理对差异的花色的靶子。

图片 22

 1     class Program
 2     {
 3         public delegate void Handler(object obj);
 4 
 5         public static void GetMessage(object message)
 6         {
 7             if (message is string)
 8                 Console.WriteLine("His name is : " + message.ToString());
 9             if (message is int)
10                 Console.WriteLine("His age is : " + message.ToString());
11         }
12 
13         static void Main(string[] args)
14         {
15             Handler handler = new Handler(GetMessage);
16             handler(29);
17             Console.ReadKey();
18         }
19    }

图片 23

运维结果

图片 24

注意寄托与其绑定方法的参数必须一至,即当 Handler 所输入的参数为 A
类型,其绑定方法 GetMessage 的参数也必须为 A 类或然 A 的父类
。相反,当绑定方法的参数为 A 的子类,系统也无能为力甄别。

 
3.陆 泛型委托

委托逆变即便实用,但若是都以 object
作为参数,则必要每回都对参数举行项目标推断,那不禁令人备感头痛。
为此,泛型委托应际而生,泛型委托具有委托逆变的优点,同时使用泛型的风味,可以使二个寄托绑定五个例外品种参数的法子,而且在措施中没有需求使用
is 实行项目剖断,从而简化了代码。

图片 25

 1     class Program
 2     {
 3         public delegate void Handler<T>(T obj);
 4 
 5         public static void GetWorkerWages(Worker worker)
 6         {
 7             Console.WriteLine("Worker's total wages is " + worker.Wages);
 8         }
 9 
10         public static void GetManagerWages(Manager manager)
11         {
12             Console.WriteLine("Manager's total wages is "+manager.Wages);
13         }
14 
15         static void Main(string[] args)
16         {
17             Handler<Worker> workerHander = new Handler<Worker>(GetWorkerWages);
18             Worker worker = new Worker();
19             worker.Wages = 3000;
20             workerHander(worker);
21 
22             Handler<Manager> managerHandler = new Handler<Manager>(GetManagerWages);
23             Manager manager = new Manager();
24             manager.Wages = 4500;
25             managerHandler(manager);
26 
27             Console.ReadKey();
28         }
29     }

图片 26

运维结果

图片 27

回来目录

4、深远解析事件

四.一 事件的案由

在介绍事件在此以前我们能够先看看上面包车型大巴例子, PriceManager
肩负对物品价位举行拍卖,当委托对象 GetPriceHandler
的重返值大于十0元,按八.八折总结,低于十0元按原价计算。

图片 28

 1     public delegate double PriceHandler();
 2 
 3     public class PriceManager
 4     {
 5         public PriceHandler GetPriceHandler;
 6 
 7         //委托处理,当价格高于100元按8.8折计算,其他按原价计算
 8         public double GetPrice()
 9         {
10             if (GetPriceHandler.GetInvocationList().Count() > 0)
11             {
12                 if (GetPriceHandler() > 100)
13                     return GetPriceHandler()*0.88;
14                 else
15                     return GetPriceHandler();
16             }
17             return -1;
18         }
19     }
20 
21     class Program
22     {
23         static void Main(string[] args)
24         {
25             PriceManager priceManager = new PriceManager();
26             
27             //调用priceManager的GetPrice方法获取价格
28             //直接调用委托的Invoke获取价格,两者进行比较
29             priceManager.GetPriceHandler = new PriceHandler(ComputerPrice);
30             Console.WriteLine(string.Format("GetPrice\n  Computer's price is {0}!",
31                 priceManager.GetPrice()));
32             Console.WriteLine(string.Format("Invoke\n  Computer's price is {0}!",
33                 priceManager.GetPriceHandler.Invoke()));
34             
35             Console.WriteLine();
36             
37             priceManager.GetPriceHandler = new PriceHandler(BookPrice);
38             Console.WriteLine(string.Format("GetPrice\n  Book's price is {0}!",
39                 priceManager.GetPrice()));
40             Console.WriteLine(string.Format("Invoke\n  Book's price is {0}!" ,
41                 priceManager.GetPriceHandler.Invoke()));
42             
43             Console.ReadKey();
44         }
45         //书本价格为98元
46         public static double BookPrice()
47         {
48             return 98.0;
49         }
50         //计算机价格为8800元
51         public static double ComputerPrice()
52         {
53             return 8800.0;
54         }
55     }

图片 29

运营结果

图片 30

观看运维的结果,倘若把信托对象 GetPriceHandler 设置为 public
,外界得以直接调用 GetPriceHandler.Invoke 获取运转结果而移除了 GetPrice方法的处理,那正是开采职员最不想见到的。
为了保障系统的封装性,开辟往往需求把信托对象 GetPriceHandler 设置为
private, 再各自进入 AddHandler,RemoveHandler 方法对 GetPriceHandler
委托对象进行李包裹装。

图片 31

 1     public delegate double PriceHandler();
 2 
 3     public class PriceManager
 4     {
 5         private PriceHandler GetPriceHandler;
 6 
 7         //委托处理,当价格高于100元按8.8折计算,其他按原价计算
 8         public double GetPrice()
 9         {
10             if (GetPriceHandler!=null)
11             {
12                 if (GetPriceHandler() > 100)
13                     return GetPriceHandler()*0.88;
14                 else
15                     return GetPriceHandler();
16             }
17             return -1;
18         }
19 
20         public void AddHandler(PriceHandler handler)
21         {
22             GetPriceHandler += handler;
23         }
24 
25         public void RemoveHandler(PriceHandler handler)
26         {
27             GetPriceHandler -= handler;
28         }
29     }
30     ................
31     ................

图片 32

为了保留封装性,诸多操作都急需进入AddHandler、RemoveHandler
那么些相似的诀窍代码,那未免令人感到厌恶。
为了尤其简化操作,事件那些概念出现。

肆.贰 事件的概念

事件(event)可被视作为一种特别的委托,它为委托对象隐式地创设起add_XXX、remove_XXX
五个点子,用作登记与注销事件的拍卖措施。而且事件对应的变量成员将会被视为
private
变量,外界无法当先事件所在对象直接待上访问它们,那使事件有所特出的封装性,而且免除了add_XXX、remove_XXX等麻烦的代码。

1     public class EventTest
2     {
3         public delegate void MyDelegate();
4         public event MyDelegate MyEvent;
5     }

调查事件的编写翻译进程可以,在编写翻译的时候,系统为 My伊夫nt
事件自动建构add_MyEvent、remove_MyEvent 方法。

图片 33

 

4.叁 事件的行使办法

事件能经过+=和-=两个法子注册只怕撤回对其拍卖的点子,使用+=与-=操作符的时候,系统会自动调用对应的
add_XXX、remove_XXX 实行管理。
值得注意,在PersonManager类的Execute方法中,即使 My伊夫nt
绑定的管理方式不为空,就能够使用My伊芙nt(string)引发事件。但借使在外边的
main 方法中平昔利用 personManager.My伊夫nt (string)
来吸引轩然大波,系统将引发错误报告。那就是因为事件有所了地道的封装性,使外围不能够赶上事件所在的靶子访问其变量成员。

注意在事变所处的对象之外,事件只可以出现在+=,-=的左边手。

 此时,开采职员无须手动增添 add_XXX、remove_XXX
的章程,就可完结与肆.一事例中的同样功用,达成了优良的包装。

图片 34

 1     public delegate void MyDelegate(string name);
 2 
 3     public class PersonManager
 4     {
 5         public event MyDelegate MyEvent;
 6 
 7         //执行事件
 8         public void Execute(string name)
 9         {
10             if (MyEvent != null)
11                 MyEvent(name);
12         }
13     }
14 
15     class Program
16     {
17         static void Main(string[] args)
18         {
19             PersonManager personManager = new PersonManager();
20             //绑定事件处理方法
21             personManager.MyEvent += new MyDelegate(GetName);
22             personManager.Execute("Leslie");
23             Console.ReadKey();
24         }
25 
26         public static void GetName(string name)
27         {
28             Console.WriteLine("My name is " + name);
29         }
30     }

图片 35

 

四.四 事件管理方法的绑定

在绑定事件处理方法的时候,事件出未来+=、-=
操作符的左侧,对应的委托对象出现在+=、-=
操作符的动手。对应以上例子,事件提供了更简便的绑定格局,只要求在+=、-=
操作符的左侧写上方式名称,系统就能够活动辩认。

图片 36

 1     public delegate void MyDelegate(string name);
 2 
 3     public class PersonManager
 4     {
 5         public event MyDelegate MyEvent;
 6         .........
 7     }
 8 
 9     class Program
10     {
11         static void Main(string[] args)
12         {
13             PersonManager personManager = new PersonManager();
14             //绑定事件处理方法
15             personManager.MyEvent += GetName;
16             .............
17         }
18 
19         public static void GetName(string name)
20         {.........}
21    }

图片 37

假使感觉编写 GetName 方法过于勤奋,你还是可以动用佚名格局绑定事件的管理。

图片 38

 1     public delegate void MyDelegate(string name);
 2 
 3     public class PersonManager
 4     {
 5         public event MyDelegate MyEvent;
 6 
 7         //执行事件
 8         public void Execute(string name)
 9         {
10             if (MyEvent != null)
11                 MyEvent(name);
12         }
13 
14         static void Main(string[] args)
15         {
16             PersonManager personManager = new PersonManager();
17             //使用匿名方法绑定事件的处理
18             personManager.MyEvent += delegate(string name){
19                 Console.WriteLine("My name is "+name);
20             };
21             personManager.Execute("Leslie");
22             Console.ReadKey();
23         }
24     }

图片 39

 

4.5 C#控件中的事件

在C#控件中存在多少个的风云,像Click、TextChanged、SelectIndexChanged
等等,多数都以经过 伊夫ntHandler 委托绑定事件的拍卖措施的,伊夫ntHandler
可说是C#控件中最分布的委托 。

public delegate void EventHandler (Object sender, EventArgs e)

伊夫ntHandler 委托并无重回值,sender 代表抓住事件的控件对象,e 代表由该事件生成的数据 。在ASP.NET中能够间接通过btn.Click+=new
伊夫ntHandler(btn_onclick) 的方法为控件绑定管理办法。

图片 40

 1 <html xmlns="http://www.w3.org/1999/xhtml">
 2 <head runat="server">
 3     <title></title>
 4     <script type="text/C#" runat="server">
 5         protected void Page_Load(object sender, EventArgs e)
 6         {
 7             btn.Click += new EventHandler(btn_onclick);
 8         }
 9 
10         public void btn_onclick(object obj, EventArgs e)
11         {
12             Button btn = (Button)obj;
13             Response.Write(btn.Text);
14         }
15     </script>
16 </head>
17 <body>
18     <form id="form1" runat="server">
19     <div>
20        <asp:Button ID="btn" runat="server" Text="Button"/>
21     </div>
22     </form>
23 </body>
24 </html>

图片 41

更加多时候,只须要在页面使用 OnClick=“btn_onclick”
方法,在编写翻译的时候系统就能够自行对事件管理方法开始展览绑定。

图片 42

 1 <html xmlns="http://www.w3.org/1999/xhtml">
 2 <head runat="server">
 3     <title></title>
 4     <script type="text/C#" runat="server">
 5         public void btn_onclick(object obj, EventArgs e)
 6         {
 7             Button btn = (Button)obj;
 8             Response.Write(btn.Text);
 9         }
10     </script>
11 </head>
12 <body>
13     <form id="form1" runat="server">
14     <div>
15        <asp:Button ID="btn" runat="server" Text="Button" OnClick="btn_onclick"/>
16     </div>
17     </form>
18 </body>
19 </html>

图片 43

 

伊芙ntHandler 只是 伊夫ntHandler<T伊芙ntArgs>
泛型委托的一个简易例子。事实上,大家能够运用
伊夫ntHandler<T伊夫ntArgs> 构造出所急需的嘱托。

public delegate void EventHandler<TEventArgs> (Object sender,
TEventArgs e)

在伊夫ntHandler<T伊芙ntArgs>中,sender代表事件源,e
代表派生自伊夫ntArgs类的事件参数。开辟职员能够创设派生自伊夫ntArgs的类,从中出席须求选用到的轩然大波参数,然后建构伊芙ntHandler<T伊芙ntArgs> 委托。

上面包车型客车例子中,先成立2个派生自伊芙ntArgs的类My伊夫ntArgs作为事件参数,然后在伊夫ntManager中树立事件my伊夫nt
, 通过 Execute 方法能够激情事件。最终在测试中绑定 my伊夫nt 的拍卖方法
ShowMessage,在ShowMessage显示my伊夫ntArgs 的事件参数 Message。

图片 44

 1     public class MyEventArgs : EventArgs
 2     {
 3         private string args;
 4 
 5         public MyEventArgs(string message)
 6         {
 7             args = message;
 8         }
 9 
10         public string Message
11         {
12             get { return args; }
13             set { args = value; }
14         }
15     }
16 
17     public class EventManager
18     {
19         public event EventHandler<MyEventArgs> myEvent;
20 
21         public void Execute(string message)
22         {
23             if (myEvent != null)
24                 myEvent(this, new MyEventArgs(message));
25         }
26     }
27 
28     class Program
29     {
30         static void Main(string[] args)
31         {
32             EventManager eventManager = new EventManager();
33             eventManager.myEvent += new EventHandler<MyEventArgs>(ShowMessage);
34             eventManager.Execute("How are you!");
35             Console.ReadKey();
36         }
37 
38         public static void ShowMessage(object obj,MyEventArgs e)
39         {
40             Console.WriteLine(e.Message);
41         }
42     }

图片 45

运作结果

图片 46

 

四.陆 为用户控件创设事件

在ASP.NET开采中,页面往往会油然则生繁多像样的控件与代码,开荒人士可以因此用户控件来防止再一次的代码。但频仍同多个用户控件,在分裂的页面中须要有差别的响应。此时为用户控件建设构造事件,便可轻易地减轻此难题。
上边例子中,在用户控件 MyControl 中国建工业总会公司立存在3个GridView控件,GridView
控件通过 GetPersonList 方法得到数据源。在用户控件中还定义了 RowCommand
事件,在 GridView 的 GridView_RowCommand
方法中激励此事件。那样,在页面使用此控件时,开荒职员就足以定义不一致的方式管理RowCommand 事件。

图片 47

 1 public class Person
 2 {
 3     public int ID
 4     { get; set; }
 5     public string Name
 6     { get; set; }
 7     public int Age
 8     { get; set; }
 9 }
10 
11 <!--    用户控件     -->
12 <%@ Control Language="C#" AutoEventWireup="true" CodeFile="MyControl.ascx.cs" Inherits="MyControl" %>
13 <script type="text/C#" runat="server">
14     protected void Page_Load(object sender, EventArgs e)
15     {
16         GridView1.DataSource = GetPersonList();
17         GridView1.DataBind();
18     }
19 
20     //绑定数据源
21     protected IList<Person> GetPersonList()
22     {
23         IList<Person> list = new List<Person>();
24         Person person1 = new Person();
25         person1.ID = 1;
26         person1.Name = "Leslie";
27         person1.Age = 29;
28         list.Add(person1);
29         ...........
30         return list;
31     }
32 
33     public event GridViewCommandEventHandler RowCommand;
34 
35     protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
36     {
37         if (RowCommand != null)
38             RowCommand(sender, e);
39     }
40 </script>
41 <div>
42    <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" 
43         onrowcommand="GridView1_RowCommand">
44       <Columns>
45           <asp:BoundField DataField="ID" HeaderText="ID"/>
46           <asp:BoundField DataField="Name" HeaderText="Name"/>
47           <asp:BoundField DataField="Age" HeaderText="Age"/>
48           <asp:ButtonField CommandName="Get" Text="Select"/>
49       </Columns>
50    </asp:GridView>
51 </div>
52 
53 <!--     页面代码       -->
54 <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default2.aspx.cs" Inherits="Default2" %>
55 <%@ Register Src="~/MyControl.ascx" TagPrefix="ascx" TagName="myControl" %>
56 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
57 
58 <html xmlns="http://www.w3.org/1999/xhtml">
59 <head runat="server">
60     <title></title>
61     <script type="text/C#" runat="server">
62        protected void myControl_RowCommand(object sender, GridViewCommandEventArgs e)
63        {
64           if (e.CommandName == "Get")
65           {
66             GridView gridView=(GridView)sender;
67             int index = int.Parse(e.CommandArgument.ToString());
68             label.Text=gridView.Rows[index].Cells[1].Text;
69           }
70        }
71    </script>
72 </head>
73 <body>
74     <form id="form1" runat="server">
75     <div>
76        <ascx:myControl ID="myControl" runat="server" OnRowCommand="myControl_RowCommand"></ascx:myControl>
77        <br />
78         Select Name : <asp:Label ID="label" runat="server"></asp:Label><br />
79     </div>
80     </form>
81 </body>
82 </html>

图片 48

运作结果

图片 49

 

利用控件已有些事件即使简单,但它界定了传送的参数类型,使开拓职员不可能传送额外的自定义参数。在结构比较复杂的用户控件中,使用已某个控件事件,分明不够便利,此时,您能够设想为用户控件组建自定义事件。
首先用户控件中包蕴订单消息与订单明细列表,首先定义2个事变参数
MyEventArgs,里面含有了订单新闻与3个 OrderItem
数组。然后创立用户控件的委托MyDelegate 与相应的事件 My伊夫nt,在 Button
的 Click 事件中激发 MyEvent 自定义事件。那样在页面管理办法
myControl_Click 中就足以经过事件参数 My伊夫ntArgs
获取用户控件中的属性,总计订单的欧洲经济共同体价格。

图片 50

  1 <!--   基础类    -->
  2  public class OrderItem
  3  {
  4      public OrderItem(string id,string goods,double price,int count)
  5      {
  6          this.OrderItemID = id;     //明细单ID
  7          this.Goods = goods;        //商品名称
  8          this.Price = price;        //商品单价
  9          this.Count = count;        //商品数量 
 10      }
 11  
 12      public string OrderItemID
 13      { get; set; }
 14      public string Goods
 15      { get; set; }
 16      public double Price
 17      { get; set; }
 18      public int Count
 19      { get; set; }
 20  }
 21  
 22  /// 事件参数
 23  public class MyEventArgs:EventArgs
 24  {
 25      public MyEventArgs(string name,string address,string tel,
 26                         string orderCode,IList<OrderItem> orderItemList)
 27      {
 28          Name = name;    //买家姓名
 29          Address = address;    //买家地址
 30          Tel = tel;    //买家电话
 31          OrderCode = orderCode;     //订单号码
 32          OrderItemList = orderItemList;     //订单明细
 33      }
 34  
 35      public string Name
 36      { get;set; }
 37      public string Address
 38      { get; set; }
 39      public string Tel
 40      { get; set; }
 41      public string OrderCode
 42      { get; set; }
 43      public IList<OrderItem> OrderItemList
 44      { get; set; }
 45  }
 46  
 47  <!--     用户控件      -->
 48  <%@ Control Language="C#" AutoEventWireup="true" CodeFile="MyControl.ascx.cs" Inherits="MyControl" %>
 49  <script type="text/C#" runat="server">
 50      protected void Page_Load(object sender, EventArgs e)
 51      {
 52          GridView1.DataSource = GetList();
 53          GridView1.DataBind();
 54      }
 55  
 56      //模拟数据源
 57      protected IList<OrderItem> GetList()
 58      {
 59          IList<OrderItem> list = new List<OrderItem>();
 60          OrderItem orderItem = new OrderItem("1", "Asus N75S", 8800, 2);
 61          list.Add(orderItem);
 62          ..........
 63          return list;
 64      }
 65  
 66      //自定义委托  
 67      public delegate void MyDelegate(object sender,MyEventArgs myEventArgs);
 68      //自定义事件 
 69      public event MyDelegate MyEvent;
 70      
 71      //按下Button时激发自定义事件
 72      protected void btn_click(object sender, EventArgs e)
 73      {
 74          if (MyEvent != null)
 75          {
 76              MyEventArgs myEventArgs = new MyEventArgs(labelName.Text, labelAddress.Text, labelTel.Text
 77                  , labelOrderCode.Text, GetList());
 78              MyEvent(this,myEventArgs);
 79          }
 80      }
 81  </script>
 82  <div>
 83     Name : <asp:Label ID="labelName" runat="server">Leslie</asp:Label><br />
 84     Address : <asp:Label ID="labelAddress" runat="server">ZhongShan University 2A 501</asp:Label><br />
 85     Tel : <asp:Label ID="labelTel" runat="server">13660123456</asp:Label><br />
 86     Order Code : <asp:Label ID="labelOrderCode" runat="server">A12012031223B0030</asp:Label><br /><br />
 87     <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" CellPadding="5">
 88        <Columns>
 89            <asp:BoundField DataField="OrderItemID" HeaderText="ID"/>
 90            <asp:BoundField DataField="Goods" HeaderText="Goods"/>
 91            <asp:BoundField DataField="Price" HeaderText="Price"/>
 92            <asp:BoundField DataField="Count" HeaderText="Count"/>
 93        </Columns>
 94     </asp:GridView>
 95     <br />
 96     <asp:Button ID="btn" runat="server" Text="Account" OnClick="btn_click"/>
 97  </div>
 98  
 99  <!--    页面处理      -->
100  <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default2.aspx.cs" Inherits="Default2" %>
101  <%@ Register Src="~/MyControl.ascx" TagPrefix="ascx" TagName="myControl" %>
102  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
103  
104  <html xmlns="http://www.w3.org/1999/xhtml">
105  <head runat="server">
106      <title></title>
107      <script type="text/C#" runat="server">
108         //在页面定义用户控件MyEvent事件的处理方法
109         protected void myControl_Click(object sender,MyEventArgs e)
110         {
111             //计算订单总体价格
112             double totalPrice=0;
113             IList<OrderItem> list=e.OrderItemList;
114             foreach(OrderItem item in list)
115                 totalPrice+=item.Price*item.Count;
116             //展示订单号及总体费用
117             labelOrderCode.Text = e.OrderCode;
118             labelTotalPrice.Text = totalPrice.ToString();
119         }
120      </script>
121  </head>
122  <body>
123      <form id="form1" runat="server">
124      <div>
125         <ascx:myControl ID="myControl" runat="server" OnMyEvent="myControl_Click"></ascx:myControl>
126         <br />
127          OrderCode : <asp:Label ID="labelOrderCode" runat="server"></asp:Label><br />
128          TotalPrice :  <asp:Label ID="labelTotalPrice" runat="server"></asp:Label>
129      </div>
130      </form>
131  </body>
132  </html>

图片 51

运作结果

图片 52

若对自定义事件不太熟练的朋友众多时候会选择 UserControl.FindControl
的主意获得用户控件中的属性,但当您深入摸底自定义事件的付出进程之后,就能够立见作用简化开发的经过。

再次回到目录

五、Lambda 表达式

5.1 Lambda 的意义

在Framework 2.0 从前,证明委托的独步一时方法是经过措施命名,从Framework 二.0
起,系统开头援救无名格局。
透过佚名格局,能够直接把1段代码绑定给事件,由此削减了实例化委托所需的编码系统开采。
而在 Framework 三.0 初叶,拉姆da
表明式起首慢慢替代了佚名格局,作为编纂内联代码的首要推荐办法。总体来讲,Lambda
表达式的效应是为着利用更轻巧的秘诀来编排匿超情势,深透简化委托的运用办法。

 

5.二 回想无名方式的应用

匿超级模特式的选取已经在四.4节大概介绍过,在此回看一下。 
选取下边包车型大巴秘技,能够通过匿名情势为Button的Click事件绑定管理办法。

图片 53

1         static void Main(string[] args)
2         {
3             Button btn = new Button();
4             btn.Click+=delegate(object obj,EventArgs e){
5                 MessageBox.Show("Hello World !");
6             };
7         }

图片 54

连天利用 delegate(){……}
的方式确立佚名方式,令人忍不住深感郁闷。于是从Framework 三.0 起, 拉姆da
表明式伊始现出。

 

伍.3 简要介绍泛型委托

在介绍 拉姆da 表明式前,先介绍一下常用的多少个泛型委托。

 

伍.三.一 泛型委托 Predicate<T>

早在Framework 贰.0 的时候,微软就为 List<T> 类增多了 Find、FindAll
、ForEach 等方式用作多少的物色。

public T Find ( Predicate<T> match)
public List<T> FindAll(Predicate<T>  match)

在这几个方法中设有二个Predicate <T>
表明式,它是三个回到bool的泛型委托,能承受多少个任意档期的顺序的靶子作为参数。

public delegate bool Predicate<T>(T obj)

在底下例子中,Predicate
委托绑定了参数为Person类的点子Match作为查询条件,然后利用 FindAll
方法查找到适当条件的 List<Person> 群集。

图片 55

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             List<Person> list = GetList();
 6             //绑定查询条件
 7             Predicate<Person> predicate = new Predicate<Person>(Match);
 8             List<Person> result = list.FindAll(predicate);
 9             Console.WriteLine(“Person count is : ” + result.Count);
10             Console.ReadKey();
11         }
12         //模拟源数据
13         static List<Person> GetList()
14         {
15             var personList = new List<Person>();
16             var person1 = new Person(1,"Leslie",29);
17             personList.Add(person1);
18             ........
19             return personList;
20         }
21         //查询条件
22         static bool Match(Person person)
23         {
24             return person.Age <= 30;
25         }
26     }
27 
28     public class Person
29     {
30         public Person(int id, string name, int age)
31         {
32             ID = id;
33             Name = name;
34             Age = age;
35         }
36 
37         public int ID
38         { get; set; }
39         public string Name
40         { get; set; }
41         public int Age
42         { get; set; }
43     }

图片 56

 

五.三.2 泛型委托 Action

Action<T> 的行使格局与 Predicate<T> 相似,差别之处在于
Predicate<T> 重返值为 bool ,  Action<T> 的重临值为 void。
Action 支持0~十五个参数,能够按必要任性使用。

public delegate void Action()
public delegate void Action<T1>(T1 obj1)
public delegate void Action<T1,T2> (T1 obj1, T2 obj2)
public delegate void Action<T1,T2,T3> (T1 obj1, T2 obj2,T3
obj3)
…………
public delegate void Action<T1,T2,T3,……,T16> (T1 obj1, T2
obj2,T3 obj3,……,T16 obj16)

图片 57

 1         static void Main(string[] args)
 2         {
 3             Action<string> action=ShowMessage;
 4             action("Hello World");
 5             Console.ReadKey();
 6         }
 7 
 8         static void ShowMessage(string message)
 9         {
10             MessageBox.Show(message);
11         }

图片 58

 

五.三.三 泛型委托 Func

寄托 Func 与 Action 相似,同样协理 0~1陆 个参数,分裂之处在于Func
必须具备重返值

public delegate TResult Func<TResult>()
public delegate TResult Func<T1,TResult>(T1 obj1)
public delegate TResult Func<T1,T2,TResult>(T1 obj1,T2 obj2)
public delegate TResult Func<T1,T2,T3,TResult>(T1 obj1,T2 obj2,T3
obj3)
…………
public delegate TResult Func<T1,T2,T3,……,T16,TResult>(T1
obj1,T2 obj2,T3 obj3,……,T16 obj16)

图片 59

 1         static void Main(string[] args)
 2         {
 3             Func<double, bool, double> func = Account;
 4             double result=func(1000, true);
 5             Console.WriteLine("Result is : "+result);
 6             Console.ReadKey();
 7         }
 8 
 9         static double Account(double a,bool condition)
10         {
11             if (condition)
12                 return a * 1.5;
13             else
14                 return a * 2;
15         }

图片 60

 

5.肆 爆料 Lambda 神秘的面纱

拉姆da 的表明式的编纂格式如下:

     x=> x * 1.5

在那之中 “ => ” 是 Lambda
表达式的操作符,在左边用作定义五个参数列表,左侧可以操作这几个参数。

事例1, 先把 int x 设置 一千,通过 Action 把表明式定义为 x=x+500
,最终通过 Invoke 激发委托。

图片 61

1         static void Main(string[] args)
2         {
3             int x = 1000;
4             Action action = () => x = x + 500;
5             action.Invoke();
6 
7             Console.WriteLine("Result is : " + x);
8             Console.ReadKey();
9         }

图片 62

事例贰,通过 Action<int> 把表明式定义 x=x+500,
到最终输入参数一千,获得的结果与例子1一律。
留意,此处拉姆da表明式定义的操作使用 { }
括弧包涵在一同,里面能够包含一多种的操作。

图片 63

 1         static void Main(string[] args)
 2         {
 3             Action<int> action = (x) =>
 4             {
 5                 x = x + 500;
 6                 Console.WriteLine("Result is : " + x);
 7             };
 8             action.Invoke(1000);
 9             Console.ReadKey();
10         }

图片 64

 

事例三,定义三个Predicate<int>,当输入值大约相当于一千则赶回 true ,
不然赶回
false。与伍.三.1的例子相比较,Predicate<T>的绑定没有要求显式创建3个方式,而是一直在Lambda表达式里实现,简洁方便了重重。

图片 65

 1         static void Main(string[] args)
 2         {
 3             Predicate<int> predicate = (x) =>
 4             {
 5                 if (x >= 1000)
 6                     return true;
 7                 else
 8                     return false;
 9             };
10             bool result=predicate.Invoke(500);
11             Console.ReadKey();
12         }

图片 66

 

事例四,在测算商品的标价时,当商品重量超过30kg则打玖折,别的按原价管理。此时得以运用Func<double,int,double>,参数1为商品原价,参数②为商品重量,最终重回值为
double 类型。

图片 67

 1         static void Main(string[] args)
 2         {
 3             Func<double, int, double> func = (price, weight) =>
 4             {
 5                 if (weight >= 30)
 6                     return price * 0.9;
 7                 else
 8                     return price;
 9             };
10             double totalPrice = func(200.0, 40);
11             Console.ReadKey();
12         }

图片 68

事例5,使用Lambda为Button定义Click事件的管理方式。与伍.2的事例相比较,使用Lambda比使用佚名情势尤其简便易行。

图片 69

1         static void Main(string[] args)
2         {
3             Button btn = new Button();
4             btn.Click += (obj, e) =>
5             {
6                 MessageBox.Show("Hello World!");
7             };
8             Console.ReadKey();
9         }

图片 70

事例陆,此处使用五.三.一的例证,在List<Person>的FindAll方法中向来运用Lambda表明式。
相比,使用拉姆da表达式,无需定义Predicate<T>对象,也不须求显式设定绑定方法,简化了不工序。

图片 71

 1      class Program
 2      {
 3         static void Main(string[] args)
 4         {
 5             List<Person> personList = GetList();
 6             
 7             //查找年龄少于30年的人
 8             List<Person> result=personList.FindAll((person) => person.Age =< 30);
 9             Console.WriteLine("Person count is : " + result.Count);
10             Console.ReadKey();
11         }
12 
13          //模拟源数据
14          static List<Person> GetList()
15          {
16              var personList = new List<Person>();
17              var person1 = new Person(1,"Leslie",29);
18              personList.Add(person1);
19              .......
20              return personList;
21          }
22      }
23  
24      public class Person
25      {
26          public Person(int id, string name, int age)
27          {
28              ID = id;
29              Name = name;
30              Age = age;
31          }
32  
33          public int ID
34          { get; set; }
35          public string Name
36          { get; set; }
37          public int Age
38          { get; set; }
39      }

图片 72

当在利用LINQ技巧的时候,随地都会弥漫着 Lambda 的身形,此时更能反映
Lambda 的长处。
但 LINQ
涉及到分档期的顺序,总部方法,IEnumerable<T>,迭代器等多地点的知识,这几个曾经超先生出本章的牵线范围。
通过这1节的介绍,希望能够援助我们更深刻地精晓 Lambda 的行使。

 回到目录

本章小结

本章首要介绍了寄托(Delegate)的行使,委托对象是多少个派生自
System.MultcastDelegate 的类,它能由此 Invoke
情势实行共同调用,也得以通过 BeginInvoke,EndInvoke
情势贯彻异步调用。而事件(伊芙nt)属于壹种尤其的信托,它与信托项目同步运用,能够简化的支出进度。
最后,本文还介绍了无名方式的使用方法,以及 Lambda 表明式的由来。

原来的文章出处:
小编:风尘浪子
原来的作品链接:
同类链接:http://…

运营结果

当创立法委员会委员托对象时,委托的参数类型必须与寄托方法相呼应。只要向建构法委员会委员托对象的构造函数中输入方法名称example.Method,委托就能一向绑定此办法。使用myDelegate.Invoke(string
message),就会显式调用委托方法。但在实质上的操作中,大家不要用到 Invoke
方法,而1旦直接行使myDelegate(string message),就能够调用委托方法。

图片 73

四.3 事件的施用方法

④.陆 为用户控件建构事件

五.四 揭示 拉姆da 神秘的面纱

事例伍,使用Lambda为Button定义Click事件的拍卖方法。与五.二的例证相比较,使用Lambda比选择匿超级模特式特别简约。

3.2 带再次回到值的委托

 

在伊芙ntHandler<T伊夫ntArgs>中,sender代表事件源,e
代表派生自伊夫ntArgs类的风浪参数。开辟职员能够创建派生自伊芙ntArgs的类,从中加入必要选取到的轩然大波参数,然后构建伊夫ntHandler<T伊芙ntArgs> 委托。

1      public class MyDelegate:MulticastDelegate
2      {
3          //同步调用委托方法
4          public virtual void Invoke();
5          //异步调用委托方法
6          public virtual IAsyncResult BeginInvoke(AsyncCallback callback,object state);
7          public virtual void EndInvoke(IAsyncResult result);
8      }

     x=> x * 1.5

在Framework 二.0 在此以前,注解委托的当世无双办法是通过措施命名,从Framework 二.0
起,系统最先帮忙匿超级模特式。
通过无名氏格局,能够一直把一段代码绑定给事件,因此削减了实例化委托所需的编码系统开拓。
而在 Framework 三.0 初始,Lambda
表明式初叶逐年替代了无名氏情势,作为编纂内联代码的首推办法。总体来讲,拉姆da
表明式的成效是为了利用更简明的格局来编排无名氏方式,深透简化委托的选用格局。

侦察事件的编写翻译进程能够,在编写翻译的时候,系统为 My伊夫nt
事件自动塑造add_MyEvent、remove_MyEvent 方法。

图片 74

假定感觉编写 GetName 方法过于费劲,你还能运用佚名格局绑定事件的管理。

 

 

 1         static void Main(string[] args)
 2         {
 3             Predicate<int> predicate = (x) =>
 4             {
 5                 if (x >= 1000)
 6                     return true;
 7                 else
 8                     return false;
 9             };
10             bool result=predicate.Invoke(500);
11             Console.ReadKey();
12         }
 1     public delegate void MyDelegate(string name);
 2 
 3     public class PersonManager
 4     {
 5         public event MyDelegate MyEvent;
 6 
 7         //执行事件
 8         public void Execute(string name)
 9         {
10             if (MyEvent != null)
11                 MyEvent(name);
12         }
13 
14         static void Main(string[] args)
15         {
16             PersonManager personManager = new PersonManager();
17             //使用匿名方法绑定事件的处理
18             personManager.MyEvent += delegate(string name){
19                 Console.WriteLine("My name is "+name);
20             };
21             personManager.Execute("Leslie");
22             Console.ReadKey();
23         }
24     }

图片 75

 

图片 76

本章主要介绍了信托(Delegate)的利用,委托对象是2个派生自
System.MultcastDelegate 的类,它能因而 Invoke
格局进行同步调用,也得以通过 BeginInvoke,EndInvoke
格局贯彻异步调用。而事件(伊芙nt)属于一种新鲜的信托,它与信托项目同步运用,可以简化的支出进度。
末尾,本文还介绍了无名格局的选拔情势,以及 拉姆da 表明式的由来。
对 .NET 开拓风乐趣的相爱的人招待加入QQ群:230564952
共同研究 !

1         static void Main(string[] args)
2         {
3             int x = 1000;
4             Action action = () => x = x + 500;
5             action.Invoke();
6 
7             Console.WriteLine("Result is : " + x);
8             Console.ReadKey();
9         }

更加多时候,只必要在页面使用 OnClick=“btn_onclick”
方法,在编写翻译的时候系统就能够自行对事件管理方法开始展览绑定。

图片 77

方法名称 说明
 Clone   创建委托的浅表副本。
 GetInvocationList   按照调用顺序返回此多路广播委托的调用列表。
 GetMethodImpl   返回由当前的 MulticastDelegate 表示的静态方法。
 GetObjectData   用序列化该实例所需的所有数据填充 SerializationInfo 对象。
 MemberwiseClone   创建当前 Object 的浅表副本。
 RemoveImpl   调用列表中移除与指定委托相等的元素

图片 78

归来目录

3.4 浅谈Observer模式

 
三.陆 泛型委托

运营结果

原创文章,转发时请评释我及出处

图片 79

壹、委托项目标原故

叁.壹 轻易的寄托

在介绍 拉姆da 表明式前,先介绍一下常用的多少个泛型委托。

图片 80

无名格局的使用已经在④.四节大致介绍过,在此回看一下。
运用上面包车型客车办法,可以经过无名方式为Button的Click事件绑定管理措施。

运作结果

当在利用LINQ技巧的时候,随处都会弥漫着 拉姆da 的身影,此时更能反映
拉姆da 的亮点。
但 LINQ
涉及到分门类,总部方法,IEnumerable<T>,迭代器等多地点的知识,那一个早已不仅本章的牵线范围。
因此这壹节的介绍,希望可以帮助我们更加深切地询问 Lambda 的行使。

在C#控件中设有多少个的轩然大波,像Click、TextChanged、SelectIndexChanged
等等,许多都以透过 伊夫ntHandler 委托绑定事件的管理方式的,伊夫ntHandler
可说是C#控件中最普及的委托 。

连日来采用 delegate(){……}
的不二等秘书诀确立佚名方式,令人忍不住感觉郁闷。于是从Framework 三.0 起, Lambda
表明式开始出现。

图片 81

 

图片 82

图片 83

  1 <!--   基础类    -->
  2  public class OrderItem
  3  {
  4      public OrderItem(string id,string goods,double price,int count)
  5      {
  6          this.OrderItemID = id;     //明细单ID
  7          this.Goods = goods;        //商品名称
  8          this.Price = price;        //商品单价
  9          this.Count = count;        //商品数量 
 10      }
 11  
 12      public string OrderItemID
 13      { get; set; }
 14      public string Goods
 15      { get; set; }
 16      public double Price
 17      { get; set; }
 18      public int Count
 19      { get; set; }
 20  }
 21  
 22  /// 事件参数
 23  public class MyEventArgs:EventArgs
 24  {
 25      public MyEventArgs(string name,string address,string tel,
 26                         string orderCode,IList<OrderItem> orderItemList)
 27      {
 28          Name = name;    //买家姓名
 29          Address = address;    //买家地址
 30          Tel = tel;    //买家电话
 31          OrderCode = orderCode;     //订单号码
 32          OrderItemList = orderItemList;     //订单明细
 33      }
 34  
 35      public string Name
 36      { get;set; }
 37      public string Address
 38      { get; set; }
 39      public string Tel
 40      { get; set; }
 41      public string OrderCode
 42      { get; set; }
 43      public IList<OrderItem> OrderItemList
 44      { get; set; }
 45  }
 46  
 47  <!--     用户控件      -->
 48  <%@ Control Language="C#" AutoEventWireup="true" CodeFile="MyControl.ascx.cs" Inherits="MyControl" %>
 49  <script type="text/C#" runat="server">
 50      protected void Page_Load(object sender, EventArgs e)
 51      {
 52          GridView1.DataSource = GetList();
 53          GridView1.DataBind();
 54      }
 55  
 56      //模拟数据源
 57      protected IList<OrderItem> GetList()
 58      {
 59          IList<OrderItem> list = new List<OrderItem>();
 60          OrderItem orderItem = new OrderItem("1", "Asus N75S", 8800, 2);
 61          list.Add(orderItem);
 62          ..........
 63          return list;
 64      }
 65  
 66      //自定义委托  
 67      public delegate void MyDelegate(object sender,MyEventArgs myEventArgs);
 68      //自定义事件 
 69      public event MyDelegate MyEvent;
 70      
 71      //按下Button时激发自定义事件
 72      protected void btn_click(object sender, EventArgs e)
 73      {
 74          if (MyEvent != null)
 75          {
 76              MyEventArgs myEventArgs = new MyEventArgs(labelName.Text, labelAddress.Text, labelTel.Text
 77                  , labelOrderCode.Text, GetList());
 78              MyEvent(this,myEventArgs);
 79          }
 80      }
 81  </script>
 82  <div>
 83     Name : <asp:Label ID="labelName" runat="server">Leslie</asp:Label><br />
 84     Address : <asp:Label ID="labelAddress" runat="server">ZhongShan University 2A 501</asp:Label><br />
 85     Tel : <asp:Label ID="labelTel" runat="server">13660123456</asp:Label><br />
 86     Order Code : <asp:Label ID="labelOrderCode" runat="server">A12012031223B0030</asp:Label><br /><br />
 87     <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" CellPadding="5">
 88        <Columns>
 89            <asp:BoundField DataField="OrderItemID" HeaderText="ID"/>
 90            <asp:BoundField DataField="Goods" HeaderText="Goods"/>
 91            <asp:BoundField DataField="Price" HeaderText="Price"/>
 92            <asp:BoundField DataField="Count" HeaderText="Count"/>
 93        </Columns>
 94     </asp:GridView>
 95     <br />
 96     <asp:Button ID="btn" runat="server" Text="Account" OnClick="btn_click"/>
 97  </div>
 98  
 99  <!--    页面处理      -->
100  <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default2.aspx.cs" Inherits="Default2" %>
101  <%@ Register Src="~/MyControl.ascx" TagPrefix="ascx" TagName="myControl" %>
102  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
103  
104  <html xmlns="http://www.w3.org/1999/xhtml">
105  <head runat="server">
106      <title></title>
107      <script type="text/C#" runat="server">
108         //在页面定义用户控件MyEvent事件的处理方法
109         protected void myControl_Click(object sender,MyEventArgs e)
110         {
111             //计算订单总体价格
112             double totalPrice=0;
113             IList<OrderItem> list=e.OrderItemList;
114             foreach(OrderItem item in list)
115                 totalPrice+=item.Price*item.Count;
116             //展示订单号及总体费用
117             labelOrderCode.Text = e.OrderCode;
118             labelTotalPrice.Text = totalPrice.ToString();
119         }
120      </script>
121  </head>
122  <body>
123      <form id="form1" runat="server">
124      <div>
125         <ascx:myControl ID="myControl" runat="server" OnMyEvent="myControl_Click"></ascx:myControl>
126         <br />
127          OrderCode : <asp:Label ID="labelOrderCode" runat="server"></asp:Label><br />
128          TotalPrice :  <asp:Label ID="labelTotalPrice" runat="server"></asp:Label>
129      </div>
130      </form>
131  </body>
132  </html>

 

 

 1         static void Main(string[] args)
 2         {
 3             Action<string> action=ShowMessage;
 4             action("Hello World");
 5             Console.ReadKey();
 6         }
 7 
 8         static void ShowMessage(string message)
 9         {
10             MessageBox.Show(message);
11         }

图片 84

图片 85

 

在底下例子中,Predicate
委托绑定了参数为Person类的法门Match作为查询条件,然后使用 FindAll
方法查找到适合条件的 List<Person> 集合。

在绑定事件管理方法的时候,事件出现在+=、-=
操作符的左侧,对应的委托对象出现在+=、-=
操作符的左边手。对应以上例子,事件提供了更简单的绑定形式,只需求在+=、-=
操作符的左侧写上方式名称,系统就可以自动辩认。

 

图片 86

重回目录

五.三.2 泛型委托 Action

五.叁.壹 泛型委托 Predicate<T>

在介绍事件在此以前我们可以先看看上面的事例, PriceManager
担当对商品价位举办管理,当委托对象 GetPriceHandler
的重临值大于100元,按捌.捌折计算,低于100元按原价总括。

运行结果

 

 

肆.4 事件管理方法的绑定

在那一个艺术中设有一个Predicate <T>
表明式,它是三个重返bool的泛型委托,能承受三个任性档案的次序的指标作为参数。

MulticastDelegate有以下多少个常用艺术:

 1         public delegate double Handler(double basicWages);
 2  
 3          public class Manager
 4          {
 5              public double GetWages(double basicWages)
 6              {
 7                  double totalWages=1.5 * basicWages;
 8                  Console.WriteLine("Manager's wages is : " + totalWages);
 9                  return totalWages;
10              }
11          }
12  
13          public class Assistant
14          {
15              public double GetWages(double basicWages)
16              {
17                  double totalWages = 1.2 * basicWages;
18                  Console.WriteLine("Assistant's wages is : " + totalWages);
19                  return totalWages;
20              }
21          }
22  
23          public class WageManager
24          {
25              private Handler wageHandler;
26  
27              //加入观察者
28              public void Attach(Handler wageHandler1)
29              {
30                  wageHandler += wageHandler1;
31              }
32  
33              //删除观察者
34              public void Detach(Handler wageHandler1)
35              {
36                  wageHandler -= wageHandler1;
37              }
38  
39              //通过GetInvodationList方法获取多路广播委托列表,如果观察者数量大于0即执行方法
40              public void Execute(double basicWages)
41              {
42                  if (wageHandler!=null)
43                     if(wageHandler.GetInvocationList().Count() != 0)
44                         wageHandler(basicWages);
45              }
46  
47              static void Main(string[] args)
48              {
49                  WageManager wageManager = new WageManager();
50                  //加入Manager观察者
51                  Manager manager = new Manager();
52                  Handler managerHandler = new Handler(manager.GetWages);
53                  wageManager.Attach(managerHandler);
54  
55                  //加入Assistant观察者
56                  Assistant assistant = new Assistant();
57                  Handler assistantHandler = new Handler(assistant.GetWages);
58                  wageManager.Attach(assistantHandler);
59  
60                  //同时加入底薪3000元,分别进行计算
61                  wageManager.Execute(3000);
62                  Console.ReadKey();
63              }
64          }

4.叁 事件的使用方法

运作结果

图片 87

若对自定义事件不太熟练的仇敌众多时候会选拔 UserControl.FindControl
的措施得到用户控件中的属性,但当您深深摸底自定义事件的付出进程之后,就会使得简化开拓的进度。

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             List<Person> list = GetList();
 6             //绑定查询条件
 7             Predicate<Person> predicate = new Predicate<Person>(Match);
 8             List<Person> result = list.FindAll(predicate);
 9             Console.WriteLine(“Person count is : ” + result.Count);
10             Console.ReadKey();
11         }
12         //模拟源数据
13         static List<Person> GetList()
14         {
15             var personList = new List<Person>();
16             var person1 = new Person(1,"Leslie",29);
17             personList.Add(person1);
18             ........
19             return personList;
20         }
21         //查询条件
22         static bool Match(Person person)
23         {
24             return person.Age <= 30;
25         }
26     }
27 
28     public class Person
29     {
30         public Person(int id, string name, int age)
31         {
32             ID = id;
33             Name = name;
34             Age = age;
35         }
36 
37         public int ID
38         { get; set; }
39         public string Name
40         { get; set; }
41         public int Age
42         { get; set; }
43     }

注意信托与其绑定方法的参数必须一至,即当 Handler 所输入的参数为 A
类型,其绑定方法 GetMessage 的参数也非得为 A 类可能 A 的父类
。相反,当绑定方法的参数为 A 的子类,系统也无力回天辨别。

本章首要介绍了寄托(Delegate)的选拔,委托对象是1个派生自
System.MultcastDelegate 的类,它能通过 Invoke
形式开始展览协同调用,也得以经过 BeginInvoke,EndInvoke
格局完毕异步调用。而事件(伊芙nt)属于一种独特的寄托,它与寄托项目同步使用,可以简化的成本进度。
最终,本文还介绍了无名氏格局的应用方法,以及 Lambda 表达式的由来。

当创设委托对象时,委托的重临值必须与寄托方法相呼应。使用下边包车型大巴例证,方法将赶回
“Hello Leslie” 。

 

图片 88

 1     public delegate void MyDelegate(string name);
 2 
 3     public class PersonManager
 4     {
 5         public event MyDelegate MyEvent;
 6         .........
 7     }
 8 
 9     class Program
10     {
11         static void Main(string[] args)
12         {
13             PersonManager personManager = new PersonManager();
14             //绑定事件处理方法
15             personManager.MyEvent += GetName;
16             .............
17         }
18 
19         public static void GetName(string name)
20         {.........}
21    }

在Framework 贰.0 从前,注明委托的唯壹方法是因此艺术命名,从Framework 二.0
起,系统起先协理佚名格局。
因此无名氏格局,能够直接把壹段代码绑定给事件,因而削减了实例化委托所需的编码系统开采。
而在 Framework 三.0 起首,拉姆da
表明式开始渐渐替代了匿有名的模特式,作为编写制定内联代码的首荐办法。总体来讲,Lambda
表明式的作用是为着利用更简便的点子来编排佚名情势,通透到底简化委托的利用办法。

初稿链接:

 

在第一节前已经提过,委托类承继于MulticastDelegate,那使委托对象帮忙多路广播,即委托对象可以绑定两个方法。当输入参数后,各样方法会按梯次进行迭代管理,并回到最终一个主意的计量结果。
上边包车型客车例证中,Price 类中有多少个总括方法,Ordinary
按一般的九.伍折计算,Favourable 按减价价 八.5折总计。委托同时绑定了那多少个办法,在输入参数十0从此,Ordinary、Favourable那四个点子将按梯次迭代实行下去,最终回到
Favourable 方法的企图结果 八5。

 1 <html xmlns="http://www.w3.org/1999/xhtml">
 2 <head runat="server">
 3     <title></title>
 4     <script type="text/C#" runat="server">
 5         public void btn_onclick(object obj, EventArgs e)
 6         {
 7             Button btn = (Button)obj;
 8             Response.Write(btn.Text);
 9         }
10     </script>
11 </head>
12 <body>
13     <form id="form1" runat="server">
14     <div>
15        <asp:Button ID="btn" runat="server" Text="Button" OnClick="btn_onclick"/>
16     </div>
17     </form>
18 </body>
19 </html>

运作结果

1         static void Main(string[] args)
2         {
3             Button btn = new Button();
4             btn.Click+=delegate(object obj,EventArgs e){
5                 MessageBox.Show("Hello World !");
6             };
7         }

图片 89

我:风尘浪子
http://www.cnblogs.com/leslies2/archive/2012/03/22/2389318.html

贰、创立法委员会委员托类

肆.一 事件的缘故

5.3.壹 泛型委托 Predicate<T>

引言

图片 90

在C#控件中存在两个的风浪,像Click、TextChanged、SelectIndexChanged
等等,多数都是由此 伊夫ntHandler 委托绑定事件的管理格局的,伊芙ntHandler
可说是C#控件中最广泛的委托 。

注意在事件所处的靶子之外,事件只好出现在+=,-=的左侧。

目录

 

事件(event)可被视作为壹种专门的嘱托,它为委托对象隐式地树立起add_XXX、remove_XXX
八个格局,用作登记与注销事件的管理方式。而且事件对应的变量成员将会被视为
private
变量,外界无法赶过事件所在对象直接待上访问它们,那使事件负有优良的封装性,而且免除了add_XXX、remove_XXX等麻烦的代码。

注重事件的编写翻译进度能够,在编写翻译的时候,系统为 My伊芙nt
事件自动营造add_MyEvent、remove_MyEvent 方法。

最终运转结果与地点的事例同样。

同类链接:

 

图片 91

 

回去目录

三、委托行使方法

四.一 事件的原因

5.三.3 泛型委托 Func

使用控件已有个别事件纵然不难,但它界定了传送的参数类型,使开荒人士不能够传送额外的自定义参数。在协会比较复杂的用户控件中,使用已某个控件事件,鲜明不够便利,此时,您能够设想为用户控件组建自定义事件。
第三用户控件中含有订单音讯与订单明细列表,首先定义二个轩然大波参数
My伊夫ntArgs,里面含有了订单消息与一个 OrderItem
数组。然后创立用户控件的委托MyDelegate 与相应的事件 My伊夫nt,在 Button
的 Click 事件中激情 My伊夫nt 自定义事件。那样在页面管理方法
myControl_Click 中就能够通过事件参数 My伊芙ntArgs
获取用户控件中的属性,总计订单的完好价格。

运营结果

拉姆da 的表明式的编纂格式如下:

事例六,此处使用伍.三.1的例子,在List<Person>的FindAll方法中向来动用拉姆da表达式。
对待,使用拉姆da表达式,无需定义Predicate<T>对象,也无需显式设定绑定方法,简化了不工序。

委托逆变即使实用,但即使都是 object
作为参数,则必要每一次都对参数举行项指标推断,那不禁令人以为头痛。
为此,泛型委托应际而生,泛型委托具有委托逆变的优点,同时使用泛型的特征,能够使1个寄托绑定八个例外连串参数的方法,而且在措施中无需利用
is 进行项目判定,从而简化了代码。

四.陆 为用户控件创设事件

 1     class Program
 2     {
 3         public delegate void Handler<T>(T obj);
 4 
 5         public static void GetWorkerWages(Worker worker)
 6         {
 7             Console.WriteLine("Worker's total wages is " + worker.Wages);
 8         }
 9 
10         public static void GetManagerWages(Manager manager)
11         {
12             Console.WriteLine("Manager's total wages is "+manager.Wages);
13         }
14 
15         static void Main(string[] args)
16         {
17             Handler<Worker> workerHander = new Handler<Worker>(GetWorkerWages);
18             Worker worker = new Worker();
19             worker.Wages = 3000;
20             workerHander(worker);
21 
22             Handler<Manager> managerHandler = new Handler<Manager>(GetManagerWages);
23             Manager manager = new Manager();
24             manager.Wages = 4500;
25             managerHandler(manager);
26 
27             Console.ReadKey();
28         }
29     }
 1 public class Person
 2 {
 3     public int ID
 4     { get; set; }
 5     public string Name
 6     { get; set; }
 7     public int Age
 8     { get; set; }
 9 }
10 
11 <!--    用户控件     -->
12 <%@ Control Language="C#" AutoEventWireup="true" CodeFile="MyControl.ascx.cs" Inherits="MyControl" %>
13 <script type="text/C#" runat="server">
14     protected void Page_Load(object sender, EventArgs e)
15     {
16         GridView1.DataSource = GetPersonList();
17         GridView1.DataBind();
18     }
19 
20     //绑定数据源
21     protected IList<Person> GetPersonList()
22     {
23         IList<Person> list = new List<Person>();
24         Person person1 = new Person();
25         person1.ID = 1;
26         person1.Name = "Leslie";
27         person1.Age = 29;
28         list.Add(person1);
29         ...........
30         return list;
31     }
32 
33     public event GridViewCommandEventHandler RowCommand;
34 
35     protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
36     {
37         if (RowCommand != null)
38             RowCommand(sender, e);
39     }
40 </script>
41 <div>
42    <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" 
43         onrowcommand="GridView1_RowCommand">
44       <Columns>
45           <asp:BoundField DataField="ID" HeaderText="ID"/>
46           <asp:BoundField DataField="Name" HeaderText="Name"/>
47           <asp:BoundField DataField="Age" HeaderText="Age"/>
48           <asp:ButtonField CommandName="Get" Text="Select"/>
49       </Columns>
50    </asp:GridView>
51 </div>
52 
53 <!--     页面代码       -->
54 <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default2.aspx.cs" Inherits="Default2" %>
55 <%@ Register Src="~/MyControl.ascx" TagPrefix="ascx" TagName="myControl" %>
56 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
57 
58 <html xmlns="http://www.w3.org/1999/xhtml">
59 <head runat="server">
60     <title></title>
61     <script type="text/C#" runat="server">
62        protected void myControl_RowCommand(object sender, GridViewCommandEventArgs e)
63        {
64           if (e.CommandName == "Get")
65           {
66             GridView gridView=(GridView)sender;
67             int index = int.Parse(e.CommandArgument.ToString());
68             label.Text=gridView.Rows[index].Cells[1].Text;
69           }
70        }
71    </script>
72 </head>
73 <body>
74     <form id="form1" runat="server">
75     <div>
76        <ascx:myControl ID="myControl" runat="server" OnRowCommand="myControl_RowCommand"></ascx:myControl>
77        <br />
78         Select Name : <asp:Label ID="label" runat="server"></asp:Label><br />
79     </div>
80     </form>
81 </body>
82 </html>

图片 92

public T Find ( Predicate<T> match)
public List<T> FindAll(Predicate<T>  match)

利用delegate就足以向来创设任何名称的寄托项目,当举行系统一编写译时,系统就能自动生成此类型。您可以行使delegate
void MyDelegate()
方式创设叁个委托类,并动用ILDASM.exe观望其成员。由ILDASM.exe
中得以见到,它三番五次了System.MulticastDelegate类,并自动生成BeginInvoke、EndInvoke、Invoke
等四个常用艺术。

委托逆变固然实用,但倘若都是 object
作为参数,则要求每一次都对参数举行项目标决断,那不由得让人感觉高烧。
为此,泛型委托应时而生,泛型委托具有委托逆变的亮点,同时使用泛型的特点,能够使3个委托绑定多少个不相同品类参数的章程,而且在点子中无需选取is 进行项目判别,从而简化了代码。

在底下例子中,Predicate
委托绑定了参数为Person类的法子Match作为查询条件,然后采取 FindAll
方法查找到适合条件的 List<Person> 集结。

图片 93

四、深切解析事件

1     public class EventTest
2     {
3         public delegate void MyDelegate();
4         public event MyDelegate MyEvent;
5     }
 1         delegate double MyDelegate(double message);
 2 
 3         public class Price
 4         {
 5             public double Ordinary(double price)
 6             {
 7                 double price1 = 0.95 * price;
 8                 Console.WriteLine("Ordinary Price : "+price1);
 9                 return price1;
10             }
11 
12             public double Favourable(double price)
13             {
14                 double price1 = 0.85 * price;
15                 Console.WriteLine("Favourable Price : " + price1);
16                 return price1;
17             }
18 
19             static void Main(string[] args)
20             {
21                 Price price = new Price();
22                 //绑定Ordinary方法
23                 MyDelegate myDelegate = new MyDelegate(price.Ordinary);
24                 //绑定Favourable方法
25                 myDelegate += new MyDelegate(price.Favourable);
26                 //调用委托
27                 Console.WriteLine("Current Price : " + myDelegate(100));
28                 Console.ReadKey();
29             }
30         }

 

1         static void Main(string[] args)
2         {
3             Button btn = new Button();
4             btn.Click += (obj, e) =>
5             {
6                 MessageBox.Show("Hello World!");
7             };
8             Console.ReadKey();
9         }
1         static void Main(string[] args)
2         {
3             int x = 1000;
4             Action action = () => x = x + 500;
5             action.Invoke();
6 
7             Console.WriteLine("Result is : " + x);
8             Console.ReadKey();
9         }
1         static void Main(string[] args)
2         {
3             Button btn = new Button();
4             btn.Click+=delegate(object obj,EventArgs e){
5                 MessageBox.Show("Hello World !");
6             };
7         }

 

五、Lambda 表达式

Action<T> 的施用方法与 Predicate<T> 相似,分化之处在于
Predicate<T> 重返值为 bool ,  Action<T> 的重回值为 void。
Action 支持0~15个参数,能够按必要率性使用。

图片 94

 

 1      public class Worker
 2      {.......}
 3      public class Manager:Worker
 4      {.......}
 5  
 6       class Program
 7      {
 8          public delegate Worker GetWorkerHandler(int id);
 9          public delegate Manager GetManagerHandler(int id);
10  
11          public static Worker GetWorker(int id)
12          {
13              Worker worker = new Worker();
14              ..............
15              return worker;
16          }
17  
18          public static Manager GetManager(int id)
19          {
20              Manager manager = new Manager();
21              ..............
22              return manager;
23          }
24  
25          static void Main(string[] args)
26          {
27              GetWorkerHandler workerHandler = new GetWorkerHandler(GetWorker);
28              var worker=workerHandler(1);
29  
30              GetManagerHandler managerHandler = new GetManagerHandler(GetManager);
31              var manager = managerHandler(2);
32              Console.ReadKey();
33          }
34      }
 1     class Program
 2     {
 3         delegate string MyDelegate(string message);
 4 
 5         public class Example
 6         {
 7             public string Method(string name)
 8             {
 9                 return "Hello " + name;
10             }
11         }
12 
13         static void Main(string[] args)
14         {
15             Example example=new Example();
16             //绑定委托方法
17             MyDelegate myDelegate=new MyDelegate(example.Method);
18             //调用委托,获取返回值
19             string message = myDelegate("Leslie");
20             Console.WriteLine(message);
21             Console.ReadKey();
22         }
23     }

归来目录

运作结果

图片 95

图片 96

图片 97

 此时,开荒职员无须手动增添 add_XXX、remove_XXX
的方法,就可达成与四.1例子中的一样作用,达成了非凡的卷入。

运维结果

 1 <html xmlns="http://www.w3.org/1999/xhtml">
 2 <head runat="server">
 3     <title></title>
 4     <script type="text/C#" runat="server">
 5         protected void Page_Load(object sender, EventArgs e)
 6         {
 7             btn.Click += new EventHandler(btn_onclick);
 8         }
 9 
10         public void btn_onclick(object obj, EventArgs e)
11         {
12             Button btn = (Button)obj;
13             Response.Write(btn.Text);
14         }
15     </script>
16 </head>
17 <body>
18     <form id="form1" runat="server">
19     <div>
20        <asp:Button ID="btn" runat="server" Text="Button"/>
21     </div>
22     </form>
23 </body>
24 </html>

图片 98

上面包车型大巴例证中,先创立三个派生自伊芙ntArgs的类My伊芙ntArgs作为事件参数,然后在伊夫ntManager中创立事件my伊芙nt
, 通过 Execute 方法能够激励事件。最终在测试中绑定 myEvent 的处理方式ShowMessage,在ShowMessage展现my伊芙ntArgs 的事件参数 Message。

图片 99

记得在利用C语言的年份,整个项目中都充满着针指的人影,那时候流行使用函数指针来成立回调函数,使用回调能够把函数回调给程序中的另一个函数。但函数指针只是简短地把地点指向另一个函数,并不可能传递其余附加音讯。
在.NET中,在许多小时里都尚未指针的人影,因为指针被封闭在里面函数在那之中。可是回调函数却还是存在,它是以信托的法子来形成的。委托能够被视为二个越来越高档的指针,它不只可以把地址指向另一个函数,而且还是能传递参数,重返值等七个音讯。系统还为委托对象自动生成了一道、异步的调用格局,开辟职员使用
BeginInvoke、EndInvoke 方法就足以丢弃 Thread 而直白动用10二线程调用 。

MulticastDelegate具备七个常用属性:Method、Target。在那之中Method
用于获取委托所代表的办法Target 用于获取当前调用的类实例。

 

注意信托与其绑定方法的参数必须一至,即当 Handler 所输入的参数为 A
类型,其绑定方法 GetMessage 的参数也务必为 A 类恐怕 A 的父类
。相反,当绑定方法的参数为 A 的子类,系统也无从甄别。

 1     public class MyEventArgs : EventArgs
 2     {
 3         private string args;
 4 
 5         public MyEventArgs(string message)
 6         {
 7             args = message;
 8         }
 9 
10         public string Message
11         {
12             get { return args; }
13             set { args = value; }
14         }
15     }
16 
17     public class EventManager
18     {
19         public event EventHandler<MyEventArgs> myEvent;
20 
21         public void Execute(string message)
22         {
23             if (myEvent != null)
24                 myEvent(this, new MyEventArgs(message));
25         }
26     }
27 
28     class Program
29     {
30         static void Main(string[] args)
31         {
32             EventManager eventManager = new EventManager();
33             eventManager.myEvent += new EventHandler<MyEventArgs>(ShowMessage);
34             eventManager.Execute("How are you!");
35             Console.ReadKey();
36         }
37 
38         public static void ShowMessage(object obj,MyEventArgs e)
39         {
40             Console.WriteLine(e.Message);
41         }
42     }

回想在行使C语言的时期,整个项目中都充满着针指的身影,那时候流行使用函数指针来创立回调函数,使用回调能够把函数回调给程序中的另一个函数。但函数指针只是简短地把地方指向另二个函数,并无法传递其余附加音信。
在.NET中,在半数以上时光里都没有指针的人影,因为指针被封闭在里面函数在那之中。可是回调函数却依然存在,它是以信托的不二秘技来产生的。委托能够被视为一个越来越高档的指针,它不止能把地方指向另二个函数,而且还是可以够传递参数,重返值等三个音讯。系统还为委托对象自动生成了伙同、异步的调用方式,开荒职员使用
BeginInvoke、EndInvoke 方法就能够废弃 Thread 而平昔动用10②线程调用 。

伊芙ntHandler 委托并无再次回到值,sender 代表抓住风浪的控件对象,e 代表由该事件生成的数据
。在ASP.NET中能够直接通过btn.Click+=new 伊芙ntHandler(btn_onclick)
的主意为控件绑定管理办法。

 1 <html xmlns="http://www.w3.org/1999/xhtml">
 2 <head runat="server">
 3     <title></title>
 4     <script type="text/C#" runat="server">
 5         public void btn_onclick(object obj, EventArgs e)
 6         {
 7             Button btn = (Button)obj;
 8             Response.Write(btn.Text);
 9         }
10     </script>
11 </head>
12 <body>
13     <form id="form1" runat="server">
14     <div>
15        <asp:Button ID="btn" runat="server" Text="Button" OnClick="btn_onclick"/>
16     </div>
17     </form>
18 </body>
19 </html>

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注