zoukankan      html  css  js  c++  java
  • C#委托及委托链

    using System;
    using System.Collections.Generic;
    using System.Text;

    /// <summary>
    /// 功能:委托链的测试
    /// 异常:无
    /// 作者:FengWei

    /// 日期:2007-06-23
    /// </summary>
    namespace Lesson63
    {
        //一、定义委托
        public delegate void MethodHandler(string str);

        class DelegateChain
        {
            //二、定义委托调用的方法
            public static void MethodA(string str)
            {
                Console.WriteLine("MethodA-->" + str);
            }

            //二、定义委托调用的方法
            public static void MethodB(string str)
            {
                Console.WriteLine("MethodB-->" + str);
            }

            //二、定义委托调用的方法
            public static void MethodC(string str)
            {
                Console.WriteLine("MethodC-->" + str);
            }

            static void Main(string[] args)
            {
                //三、定义委托对象
                MethodHandler call = null;

                call += new MethodHandler(MethodA);
                call += new MethodHandler(MethodB);
                call += new MethodHandler(MethodC);

                //四、委托方法被调用
                call("委托方法被调用");

                Console.ReadLine();
            }
        }
    }

     


     

    using System;
    using System.Collections.Generic;
    using System.Text;

    /// <summary>
    /// 功能:委托的测试
    /// 异常:无
    /// 作者:FengWei
    /// 日期:2007-06-23
    /// </summary>
    namespace Lesson63
    {
        //第一步:定义委托
        //public delegate void MethodHandler(string name);

        class DelegateTest
        {
            //第二步:定义运行时预调用的方法 MethodA
            public static void MethodA(string name)
            {
                Console.WriteLine("MethodA-->" + name);
            }

            //第二步:定义运行时预调用的方法 MethodB
            public static void MethodB(string name)
            {
                Console.WriteLine("MethodB-->" + name);
            }

            //第二步:定义运行时预调用的方法 MethodC
            public static void MethodC(string name)
            {
                Console.WriteLine("MethodC-->" + name);
            }

            public static void Main()
            {
                //第三步:委托与方法相联系(创建delegate类型实例,传入预调用

                          的方法
                MethodHandler callA = new MethodHandler(MethodA);
                MethodHandler callB = new MethodHandler(MethodB);
                MethodHandler callC = new MethodHandler(MethodC);

                //第四步:委托调用方法
                callA("MethodA被调用");
                callB("MethodB被调用");
                callC("MethodC被调用");

                Console.ReadLine();
            }
        }
    }

     


     

    using System;
    using System.Collections.Generic;
    using System.Text;

    /// <summary>
    /// 功能:多点传送(同一事件的处理采用多个方法实现)
    /// 异常:无
    /// 作者:FengWei
    /// 日期:2007-06-23
    /// </summary>
    namespace Lesson63
    {
        //定义委托
        public delegate void MyMethodHandler(int i);

        public class MyEvent
        {
            //定义事件
            public event MyMethodHandler SomeEvent;
           
            //定义方法来触发事件
            public void onSomeEvent(int i)
            {
                if(SomeEvent!=null)
                {
                    //触发事件
                    SomeEvent(i);
                }
            }
        }

        class X
        {
            //被委托的方法
            public void ShowX(int i)
            {
                Console.WriteLine("ShowX()-->" + i);
            }
        }

        class Y
        {
            //被委托的方法
            public void ShowY(int i)
            {
                Console.WriteLine("ShowY()-->" + i);
            }
        }

        class Run
        {
            public static void RunShow(int i)
            {
                 Console.WriteLine("RunShow()-->" + i);
            }

            public static void Main()
            {
                X x = new X();
                Y y = new Y();
                MyEvent myEvent = new MyEvent();

                //多点注册
                myEvent.SomeEvent+=new MyMethodHandler(RunShow);
                myEvent.SomeEvent+=new MyMethodHandler(x.ShowX);
                myEvent.SomeEvent += new MyMethodHandler(y.ShowY);
                Console.WriteLine("注册了三个方法RunShow ShowX ShowY");

                //调用触发事件的方法
                myEvent.onSomeEvent(8);

                //取消一个注册
                myEvent.SomeEvent -= new MyMethodHandler(y.ShowY);
                Console.WriteLine("注销了y.ShowY方法后");

                //调用触发事件的方法
                myEvent.onSomeEvent(6);

                Console.ReadLine();
     

    础:
        1. .net框架约定,所有保存事件信息的类型都应该继承自System.EventArgs,并且类型名称应该以EventArgs结尾;委托类型应该以EventHandler结束,回调方法原型应该有一个void返回值,并且接受两个参数, 第一个Object指向发送通知的对象;第二个参数继随自EventArgs类型,包括接受者需要的附加信息。
         2.如果定义的事件没有传递 给事件接收者的附加信息,便不必定义新的委托,直接使用System.EventHandler,并将EventArgs.Empty传递给第2个参数即可
    public delegate void EventHandler(Object sender, EventArgs e);

    .net框架程序设计
    最简间的事件与委托关联

    //定义委托
    public delegate void RequestHandler(string Url);
    //定义委托类型的事件
    public event RequestHandler RequestEvent;
    //定义事件处理程序,即委托的回调方法
    public void RequestMothed(string url)
    {
        
    //do what you want to do;
    }

    //将事件处理程序添加到委托链
    RequestHandler handler = new RequestHandler(RequestMothed);
    //将委托对象添加到事件链中,删除委托对象用 -=
    RequestEvent += handler;
    //引发事件,可将事件当一个方法看待,参数必须与前面声明的一致
    RequestEvent(stringTest);

    事件可用的修饰符:

    Static   Virtual    Override    Abstract

    Static类似于字段,类的甩的对象共享静态事件,当引用这类事件时,必须用类名称而不是名称


    一:登记事件
    定义一个收邮件的类MailManager,在MailManager中定义一个收到邮件便触发的事件MailMSG,传真fax寻呼pager等对象在登记MailManager和MailMSG事件,当新电子邮件到达时,MailManager将通知发送给所有登记对象,这些对象按自己的方法处理。  开始代码.

    class MailManager
    {
       
    //在MailManager类中定义MailMsgEventArgs类型
       public class MailMsgEventAgrs:EventArgs
       
    {
            
    public MailMsgEventArgs(string from, string to, string subject, string body)
            
    {
                
    this.from=from;
                
    this.to=to;
                
    this.subject=subject;
                
    this.body=body;
            }

            
    public readonly string from, to, subject, body;
       }


       
    //定义委托
        public delegate void MailMsgEventHandler(Object sender, MailMsgEventArgs args);

       
    //定义委托类型 的事件
       public event MailMsgEventHandler MailMsg;

       
    //此方法发出通知,即有邮件是通知FAX和PAGER  ,Fax和PAGER类可以重写些方法
       public virtual void OnMailMsg(MailMsgEventArgs e)
       
    {
          
    //判断是否有对象登记事件
          if(MailMsg != null)
          
    {
              
    //如果有,则通知委托链表上的所有对象
              MailMsg(this, e);
          }

         
       }

       
       
    //此方法在新电子邮件到达到被触发
       public void SimulateArrivingMsg(string from, string to, string subject, string body)
       
    {
                MailMsgEventArgs e 
    = new MailMsgEventArgs(from, to, subject, body);
                OnMailMsg(e);
       }

    }

    其中   编辑器编译public event MailMsgEventHandler MailMsg;时,会产生
    二:侦听事件

    class Fax
    {
       
    //将MailManager对象传递给构造器
        public Fax(MailManager mm)
        
    //将回调函数与事件关联
        mm.MailMsg += new MailManager.MailMsgEventHandler(FaxMsg);
        
    //回调函数
              {
            
    //sender 表示MailManagercf 对象,如果要和事件触发者通信,将用到此参数
             
    //MailManager 对象希望提供的一些附加事件信息
             
    //Fax内部的处理
             Console.WriteLine("Form:{0}\n To:{1}\n Subject: {2}\n: {3}\n", e.from, e.to, e,subject, e.body);
        }

        

        public void Unregister(MailManager mm)
       
    {
             //构造一个指向FaxMsg回调方法垢MailMsgEventHandler委托实例
          MailManager.MailMsgEventHandler callback 
    = new MailManager.MalMsgEventHandler(FaxMsg);
          
    //注销MailManager的MailMsg事件
           mm.MailMsg -= callback;
       }

    }


    其中,编辑器处理mm.MailMsg += new MailManager.MailMsgEventHandler(FaxMsg);
    时会将它转换为

    mm.add_MailMsg(new MailManager.MailMsgEventHandler(FaxMsg));
    //调用了前面public event MailMsgEventHandler MailMsg编辑的产生的代码  public virtual void add_MailMsg()方法,所以此方法里面有一个是MailMsgEventHandler委托的实例。


    三:显式控制事件注册,实际上就将public event MailMsgEventHandler MailMsg编辑时产生的内部代码源码化

    Class MailManager
    {
       
    //传给事件接受者的类型信息,类似于前的
       public class MailMsgEventAgrs : EventArgs{..}
       
    //定义委托
       public delegate void MailMsgEventHandler(Object sender, MailMsgEventArgs args);

      
    //变化发生在这里,和前面编辑器内部产生代码一样
       private MailMsgEventHandler mailMesgEventHandlerDelegate;
      
    //显式定义事件及其访问器的方法
       public event MailMsgEventHandler MailMsg
       
    {
          add
          
    {
             mailMsgEventHandlerDelegate
    =(MailMsgEventHandler)Delegate.Combine(mailMsgEventHandlerDelegate, value);;
          }

          
    //将传入的事件处理器(value)从委托链表上移除
           remove
          
    {
             mailMsgEventHandlerDelegate 
    = (MailMsgEventHandler)Delegate.Remove(mailMsgEventHandlerDelegate, value);
          }

       }

       
    //下面受保护的虚方法负责通知事件的登记对象,这里已经不是事件而是一个委托类型 的字段了
       
    //有点难以理解
        protected virtual void onMailMsg(MailMsgEventArgs e)
        
    {
           
    if(mailMsgEventHandlerDelegate != null)
           
    {
                        mailMsgEventHandlerDelegate(
    this, e);
           }

        }

        
    //在新电子邮件到达时被调用
        public void SimulateArrivingMsg(string from, string to, string Subject, string body)
        
    {.}
    }

    至于为什么要用委托,可以从上面看出,它是类型安全的,因为一个函数指针的非正常调用可能会有未知的实现。

    事件的发生只会激发某个动作(如果有),而具体要做什么,这就是委托实例的调用列表中的方法的执行。两者从概念上讲没有共同点。所以你没区分清楚是因为还没有真正理解它们重要的用途。
    委托链
          委托的Invoke()方法,在委托链上,具有调用一个委托对象之前的委托对象(如果存在)的能力,这样,可以确保委托链上所有的委托对象都得到调用。但它的缺点是:只能取得最后一个调用对象的返回值,而前面调用对象的返回值都会丢失;另外,如果中间有一个委托对象产生异常或阻塞很长的时间,则会阻止其后面所有的委托对象的调用,因为委托链上的对象是按序调用的。
    针对此种情况,MulticastDelegate类提供一个实例方法:GetInvocationList(),它返回一个委托形式的数组,从而可以任意调用委托链上的对象。

    using System;
    using System.Text;

    namespace delegateStudy
    {
        
    class aClass
        
    {
            
    public string A()
            
    {
                Console.WriteLine(
    "Write A");
                
    return "this is A";
            }

        }

        
    class bClass
        
    {        
            
    public string B()
            
    {
                Console.WriteLine(
    "Write B");
                
    return "this is B";
            }

        }

        
    class cClass
        
    {
            
    public string C()
            
    {
                Console.WriteLine(
    "Write C");
                
    return "this is C";
            }

        }

        
    class delegateStudy
        
    {        
            
    delegate string GetReturnValue();  //定义
            static void Main()
            
    {
                
    //声明一个空委托
                GetReturnValue getReturn = null;
                
    //将上面三个方法添加到委托链上
                getReturn +=  new GetReturnValue(new aClass().A);
                getReturn 
    +=  new GetReturnValue(new bClass().B);
                getReturn 
    +=  new GetReturnValue(new cClass().C);           
                Why(getReturn);
            }

            
    static void Why(GetReturnValue grv)
            
    {
                
    //委托为空则什么事也不做
                if(grv == nullreturn;
                
    //获取一个由委托链上对象组成的数据,用GetInvocationList()方法
                Delegate[] arrayOfDelegate = grv.GetInvocationList();
                
    foreach(GetReturnValue getR in arrayOfDelegate)
                
    {
                    Console.WriteLine(getR());                
                }

                  
    //取得对应委托对象的回调方法名
                Console.WriteLine(arrayOfDelegate[2].Method);
                 
    //输出对应委托对象回调方法属于哪个名称空间和类,这里输出为delegateStudy.bClass
                Console.WriteLine(arrayOfDelegate[1].Target);
                
    //调用arrayOfDelegate[0]位置委托对象的回调方法,传对应参数,没有参数为null
                
    //执行了aClass里的A()  
                Console.WriteLine(arrayOfDelegate[0].DynamicInvoke(null));
                Console.Read();
            }

        }

    }

  • 相关阅读:
    mybatis强化(二)Parameters和Result
    operator new 和 new operator
    hdu 1007 Quoit Design 分治求最近点对
    实现一个简单的shared_ptr
    bzoj 3224: Tyvj 1728 普通平衡树 替罪羊树
    bzoj 2648 SJY摆棋子 kd树
    hdu 2966 In case of failure k-d树
    codeforces 713D D. Animals and Puzzle 二分+二维rmq
    bzoj 1188 : [HNOI2007]分裂游戏 sg函数
    bzoj 1912 : [Apio2010]patrol 巡逻 树的直径
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/1801910.html
Copyright © 2011-2022 走看看