标签:
委托是一个或多个函数指针的抽象。由于有了委托,我们就可以将函数当做数据来看待,包括使用委托作为变量,参数或者数据成员。它可以保护我们的代码,还可以用于回调,事件和线程。。。。。。
委托使函数能够作为参数进行传递,能够作为值从另外一个函数返回,甚至能够存储到一个数组当中,完完全全就是一个数据。不过比C和C++中的函数指针更为安全和可靠。
一个委托的实例封装一个函数引用和一个目标对象。当一个委托被激活时,委托就调用它所封装的那个对象上的函数。
委托有一个签名(参数列表)和一个返回类型。添加到委托的函数必须与其一致。
委托的定义(关键字delegate):
访问修饰符 delegate 返回类型 委托类型名(参数列表(签名));
public delegate void MyHandler(string name);
定义了一个参数为string,返回类型为void的委托。
看一下怎么使用
public class FunctionClass { public void Function1(string name) { Console.WriteLine("{0},你好", name); } } ///////使用 // MyHandler handler = new MyHandler(new FunctionClass().Function1); MyHandler handler=new FunctionClass().Function1;//委托支持隐式实例化 handler.Invoke("RanRan");//激发委托 等同于handler("RanRan")
委托除了Invoke方法,还有其它的很多激发方法,如beginInvoke endInvoke 这两个主要是用于异步委托,在另一篇文章中有介绍,在此就不讲了。
在这儿补充.net3.5以后新增的两个比较全能的委托
Func<>委托和Action<>委托
两者都可以用作各种签名的函数的委托,省去自己定义委托的代码,二者主要区别是:Func<>委托的函数有返回类型,Action委托的函数没有返回类型!!!
1.Func<T1,T2,...TResult>
2.Action<T1,T2...>
具体看下面如何使用:
public class FunctionClass { public static bool Function2(string name) { Console.WriteLine("{0},how do you do", name); return true; } public static void Function3(string name) { Console.WriteLine("{0},How do you do", name); } } ////使用: ///Func委托的函数有返回类型 Func<string, bool> handler2 = new Func<string, bool>(FunctionClass.Function2); handler2.Invoke("Fan"); ///Action委托的函数没有返回类型 Action< string> handler3=new Action<string>(FunctionClass.Function3); handler3.Invoke("HuaRan");
继续委托的讲解 :
委托实际上并不仅仅是一个函数指针的作用,而是一个函数指针链表的作用。一个委托可以委托N多个函数,灵活使用+=,-=,这是一个队列的结构,先进先出,先委托先激发,不过要注意,它只返回最后一个参数的返回值。
见下面的代码:
public class HandlerFunc { public static void Fun1() { Console.WriteLine("T‘m Fun1"); } public static void Fun2() { Console.WriteLine("I‘m Fun2"); } public static void Fun3() { Console.WriteLine("I‘m Fun3"); } } /////使用 Action Handler4 = HandlerFunc.Fun1; Handler4 += HandlerFunc.Fun2; Handler4 += HandlerFunc.Fun3; Handler4.Invoke();
运行结果:
最后补充委托的两个知识点
一 委托变量的定义和赋值有三种方式
1.传统的委托,上面的代码都是
2.匿名函数
3.Lambda表达式
2和3用着非常方便,而且一般会和Func或者Action一起使用,当然在某些地方有他的不足。
//传统委托: MyHandler handler = new FunctionClass().Function1; //匿名方法 MyHandler handler2=delegate (string name) { Console.WriteLine("{0},你好", name); }; //利用Func和Action也可以,下面的也是匿名方法 Action<string> handler4 = delegate(string name) { Console.WriteLine("{0},你好", name); }; //利用Lanbda表达式 (参数)=>(语句) Action<string> handler = (name) => Console.WriteLine("{0},你好", name);
二 委托尊崇参数引用的原则 即ref和out.
事件
事件是指通知。
事件拥有发布者和订阅者
订阅者就是值通知,产生事件。
事件拥有订阅者,订阅者通过添加到事件的委托来注册事件。
发布者通过调用该委托的函数应用来通知订阅者,然后订阅者对事件进行响应(通过在函数的代码中表示出来)
事件的关键字是event,
定义的语法:
访问修饰符 event 委托类型名 事件名;
EventHandler编译器自带的委托,处理标准事件程序
EventArgs及其派生类中存储有关事件的信息
具体实现看下面的代码(银行账户透支时引发NSF事件,BankEventArgs类提供银行账户余额和导致账户透支的交易额)
//定义一个委托,里面存储事件处理的代码,e中存储了事件的信息 public delegate void OverDrawn(object o,BankEventArgs e); //有关事件信息的类 继承自EventArgs public class BankEventArgs:EventArgs { //关于存款 private decimal propBalance; public decimal Balance { get{return propBalance;} } //关于花费 private decimal propTransaction; public decimal Transaction { get{return propTransaction;} } //构造函数 public BankEventArgs(decimal amountBalance,decimal amountTransaction) { this.propBalance=amountBalance; this.propTransaction=amountTransaction; } } public class Bank { //定义一个NSF事件 public event OverDrawn NSF; //定义一个存款字段 private decimal propBalance=0; //定义一个存款属性 只读的 public decimal Balance { get{return propBalance;} } //定义一个存款函数 public decimal Deposit(decimal amountDeposit) { propBalance+=amountDeposit; return propBalance; } //定义一个引发事件的函数 public decimal WithDrwal(Decimal amountWithDraw) { //新存款=旧存款-花费 decimal newBalance=propBalance-amountWithDraw; //如果存款为负 引发事件 if(newBalance<0) { if(NSF!=null) { //实例化一个事件信息的对象 将事件信息存入 BankEventArgs args=new BankEventArgs(Balance,amountWithDraw); // 引发事件 NSF(this,args); } } //更改存款字段 return propBalance=newBalance; } } /////使用 //实例化 Bank account=new Bank(); //事件订阅 account.NSF+=NSFHandler; //存款5000 account.Deposit(5000); //花费7220 这当中会引发事件 account.WithDrwal(7220); Console.ReadKey(); //订阅者 进行事件发生后的处理 public static void NSFHandler(object o,BankEventArgs e) { Console.WriteLine("NSF Transaction"); Console.WriteLine("Balance:"+e.Balance); Console.WriteLine("Transaction:"+e.Transaction); }
这就是事件的核心含义,虽然可以通过函数调用实现,不过事件更为标准,更为有逻辑性,写事件是非常有必有的!!!!
标签:
原文地址:http://www.cnblogs.com/Huaran1chendu/p/4857068.html