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();
        }

    }

}

原文地址:https://www.cnblogs.com/Leo_wl/p/1801910.html