一. 委托delegate
1.理解委托
可以将委托delegate理解为函数指针,声明一个委托,实际上就是声明一个指向绑定函数的指针。当然,C#中是没有指针这个概念的,这种类比可以方便自己理解。
比如,小绿委托小蓝帮自己买一杯酸奶,动作的最终执行者实际是小蓝,小绿只需要告知小蓝,成功建立起联系即可。
1 class cc
2 {
3
4 public static void Addt(int a,int b)
5 {
6 int c = a + b;
7 Console.WriteLine("The value of a plus b is {0}", c);
8 Console.ReadKey();
9 }
10
11 }
12
13 class Program
14 {
15 //声明一个代理
16 public delegate void MyDelegateEventHander(int a, int b);
17
18 static void Main()
19 {
20 //实例化一个代理,代理的具体实现由Add()方法完成
21 MyDelegateEventHander md = new MyDelegateEventHander(cc.Add);
22 md(1,1);
23 }
24 }
2.委托的实现
实现一个delegate是很简单的,通过以下3个步骤即可实现一个delegate:
(1)声明一个delegate对象,它应当与你想要传递的方法具有相同的参数和返回值类型。
声明一个代理的例子:
public delegate int MyDelegate(string message);
(2)创建delegate对象,并将你想要传递的函数作为参数传入。
创建代理对象的方法:
1). MyDelegate myDelegate = new MyDelegate(实例名.方法名);
2). MyDelegate myDelegate = new MyDelegate(类名.方法名);
注:如果需要代理的方法是一个static静态方法的话,采用第2种方式,否则采用第1种方式。
(3)在要实现异步调用的地方,通过上一步创建的对象来调用方法。
可以直接使用代理调用代理所指向的方法:
myDelegate(向方法传递的参数);
即:a.生成自定义代理类:delegate int MyDelegate();
b.然后实例化代理类:MyDelegate d = new MyDelegate(MyClass.MyMethod);
c.最后通过实例对象调用方法:int value = d();
3. 需要注意的事情
“代理”(delegate)(代表、委托):“代理”是类型安全的并且完全面向对象的。
(1)在C#中,所有的代理都是从System.Delegate类派生的(delegate是System.Delegate的别名)。
(2)代理隐含具有sealed属性,即不能用来派生新的类型。
(3)代理最大的作用就是为类的事件绑定事件处理程序。
(4)在通过代理调用函数前,必须先检查代理是否为空(null),若非空,才能调用函数。
(5)在代理实例中可以封装静态的方法也可以封装实例方法。
(6)在创建代理实例时,需要传递将要映射的方法或其他代理实例以指明代理将要封装的函数原型(.NET中称为方法签名:signature)。注意,如果映射的是静态方法,传递的参数应该是类名.方法名,如果映射的是实例方法,传递的参数应该是实例名.方法名。
(7)只有当两个代理实例所映射的方法以及该方法所属的对象都相同时,才认为它们是想等的(从函数地址考虑)。
(8)多个代理实例可以形成一个代理链,System.Delegate中定义了用来维护代理链的静态方法Combion,Remove,分别向代理链中添加代理实例和删除代理实例。
(9)代理的定义必须放在任何类的外面,如delegate int MyDelegate();而在类的方法中调用MyDelegate d = new MyDelegate(MyClass.MyMethod);来实例化自定义代理的实例。
4. 匿名方法
匿名方法是在初始化委托时内联声明的方法。
基本结构:
deleage( 参数 ) { 语句块 }
例如:
delegate int MyDel (int x); //定义一个委托
MyDel del = delegate( int x){ return x; };
从上面我们可以看到,匿名方法是不会显示声明返回值的。
5.Lambda表达式
Lambda表达式主要用来简化匿名方法的语法。在匿名方法中,delegate关键字有点多余,因为编译器已经知道我们将方法赋值给委托。通过几个简单步骤,我们就可以将匿名方法转换为Lambda表达式:
- 删除delegate关键字
- 在参数列表和匿名方法主体之间防Lambda运算符=>。Lambda运算符读作"goes to"。
MyDel del = delegate( int x) { return x; };//匿名方法
MyDel del2 = (int x) => {return x;};//Lambda表达式
MyDel del3 = x => {return x};//简写的Lambda表达式
6. 用Action<T>和Func<T>,第一个无返回值
Func<参数1, 参数2, 返回值> 委托名= ((参数1,参数2) => {带返回值的方法体 });返回值=委托名(参数1,参数2);
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace @delegate { public delegate int Call(int num1, int num2); class SimpleMath { // 乘法方法 public static int Multiply(int num1, int num2) { return num1 * num2; } // 除法方法 public int Divide(int num1, int num2) { return num1 / num2; } } class Test { static void Main(string[] args) { //--------------------第一种写法------------------------// //Call objCall = new Call(SimpleMath.Multiply); //Call objCall1 = new Call(new SimpleMath().Divide); //--------------------第二种写法------------------------// //Call objCall = SimpleMath.Multiply; //Call objCall1 = new SimpleMath().Divide; //--------------------第三种写法------------------------// //Call objCall = delegate(int a, int b) //{ // return a * b; //}; //Call objCall1 = delegate(int a, int b) //{ // return a / b; //}; //--------------------第四种写法------------------------// //Call objCall =((int a,int b)=> { return a*b;}); //Call objCall1 = ((int a, int b) => { return a / b; }); //--------------------第五种写法------------------------// Func<int, int, int> objCall = ((a, b) => { return a * b; }); Func<int, int, int> objCall1 = ((a, b) => { return a / b; }); Action<int, int> ob = ((a, b) => { Console.WriteLine(a * b); }); ob(5, 3); //----------------------------------------------------// int result = objCall(5, 3); int result1 = objCall1(5, 3); System.Console.WriteLine("结果1为 {0},结果2为{1}", result, result1); Console.ReadKey(); } } }
BTW:事件驱动程序的组成,主要是有对象、事件和事件处理程序三个要素。对象就是完成任务的主体,比如说一个控件Button1;事件么,就是对象要执行的任务,比如单击,就是click事件;那么事件处理程序就是Button1_Click这段程序了。
二. 事件event
C#中的事件就是代理的一个变量。它和属性、方法一样,都是类的成员。只不过事件是指向一个方法,当事件被触发时,就会执行对象的相关方法。
事件的这种对方法的引用并不是写死在代码里面的,而是可以进行更改的。辟如:我们在DotNet中按钮的OnClick事件,它可以指向符合OnClick事件签名的任何一个方法。
1.事件的定义使用event关键字:
private delegate void CryHandler();
public event CryHandler DuckCryEvent;
从上面的代码我们可以看出来:事件就是一个代理类型的变量。
2.指定事件处理程序:
指定事件处理程序就是为事件挂接方法的过程。
DuckCryEvent +=new CryHandler(Cry); //注册事件,传入方法
public void Cry()
{
Console.WriteLine("我是一只小鸭,呀依呀依呀....");
}
3.执行事件
执行事件就是调用事件所指向方法的过程。一般对事的执行代码写在相应的方法或属性中,如果方法或属性被调用时就触发事件。
public void BeShaked() //事件需要在方法中被触发
{
DuckCryEvent();
}