码迷,mamicode.com
首页 > 其他好文 > 详细

委托和事件

时间:2015-10-06 15:20:41      阅读:222      评论:0      收藏:0      [点我收藏+]

标签:

委托是一个或多个函数指针的抽象。由于有了委托,我们就可以将函数当做数据来看待,包括使用委托作为变量,参数或者数据成员。它可以保护我们的代码,还可以用于回调,事件和线程。。。。。。

委托使函数能够作为参数进行传递,能够作为值从另外一个函数返回,甚至能够存储到一个数组当中,完完全全就是一个数据。不过比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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!