• CLR via C# 读书笔记 委托


    初识委托

    委托是一种定义方法签名的类型。实例化委托时,可以将其实例与任何具有兼容签名的方法相关联。通过委托实例调用方法。委托用于将方法作为参数传递给其他方法。事件处理就是通过委托调用的方法

    声明一个委托

    //声明一个委托类型
    //方法获取2个Int32类型的参数 ,返回值为void
    public
    delegate void PerformCalculation(int num1, int num2);

    使用委托

    直接上代码:

    View Code
            //声明委托 
            internal delegate void PerformCalculation(int num1, int num2);
           
            static void Main(string[] args)
            {
                //创建委托对象 new运算符实例化委托
                PerformCalculation myDelegate = new PerformCalculation(Add);
                //调用委托
                myDelegate(100, 100);
                Program p = new Program();
                CallBack(1000, 10, p.Division);
                //快捷语法实例化委托
                PerformCalculation myDelegate1 = Minus;
                myDelegate1(200, 10);
    
                ChainDelegateDemo1(p);
                ChainDelegateDemo2(p);
                Console.ReadKey();
            }
            public static void ChainDelegateDemo1(Program p)
            {
                Console.WriteLine("****** chain delegate demo ******");
                PerformCalculation pc1=new PerformCalculation (Add);
                PerformCalculation pc2 = new PerformCalculation(Minus);
                PerformCalculation pc3 = new PerformCalculation(p.Division);
                PerformCalculation pc4 = new PerformCalculation(Multiply);
                PerformCalculation pcChain = null;
                pcChain = (PerformCalculation)Delegate.Combine(pcChain, pc1);
                pcChain = (PerformCalculation)Delegate.Combine(pcChain, pc2);
                pcChain = (PerformCalculation)Delegate.Combine(pcChain, pc3);
                pcChain = (PerformCalculation)Delegate.Combine(pcChain, pc4);
                pcChain(100, 50);
            }
    
            public static void ChainDelegateDemo2(Program p)
            {
                Console.WriteLine("****** chain delegate demo2 ******");
                PerformCalculation pc1 = new PerformCalculation(Add);
                PerformCalculation pc2 = new PerformCalculation(Minus);
                PerformCalculation pc3 = new PerformCalculation(p.Division);
                PerformCalculation pc4 = new PerformCalculation(Multiply);
                PerformCalculation pcChain = null;
                pcChain += pc1;
                pcChain += pc2;
                pcChain += pc3;
                pcChain += pc4;
                pcChain(200, 100);
            }
    
            public static void CallBack(int num1, int num2, PerformCalculation cal)
            {
                if (cal!=null)
                {
                    cal(num1, num2);
                }
            }
            public static void Add(int num1, int num2)
            {
                Console.WriteLine(num1 + num2);
            }
            public static void Multiply(int num1, int num2)
            {
                Console.WriteLine(num1 * num2);
            }
            public static void Minus(int num1, int num2)
            {
                Console.WriteLine(num1 - num2);
            }
            public void Division(int num1, int num2)
            {
                Console.WriteLine(num1 / num2);
            }
      

    Program 类定义了静态方法CallBack。CallBack方法获取2个Int32类型的整数,一个PerformCalculation委托对象的引用。CallBack内部地用 cal变量指定的回调方法。Program 类中Add、Multiply、Minus为静态方法,Division为实例方法。

    总结:

    • 委托声明使用关键字delegate,与方法相似又返回值和签名,但是没有方法体
    • 实例化委托对象时可以使用new运算符,也可以是用快捷语法

    委托揭秘

    编译器生成的代码:

    1、声明的委托PerformCalculation被编译成同名的类,包含一个构造器,3个方法(BeginInvoke、EndInvoke、Invoke),完整的PerformCalculation类

        internal class PerformCalculation : System.MulticastDelegate
        {
            public PerformCalculation(object obj, IntPtr method);
    
            public virtual void Invoke(Int32 num1, Int32 num2);
    
            public virtual IAsyncResult BeginInvoke(Int32 num1,Int32 num2,AsyncCallback callback,Object obj);
     
            public virtual void EndInvoke(IAsyncResult result);
    
        }

    2、所有的委托都派生自System.MulticastDelegate类,System.MulticastDelegate派生自System.Delegate类。

     System.MulticastDelegate类的3个重要的非公共字段  

    字段

    类型

    说明
    _target System.Object

    当委托对象包装一个静态方法时,这个字段为null。当委托对象包装一个实例方法时,这个字段引用的回调方法要操作的对象。

    换言之,这个字段指出要传给实例方法的隐式参数this的值

    _methodPtr   System.IntPtr 一个内部的整数值,CLR用它标识要回调的方法
    _invocationList System.Object 该字段通常为null。构造一个委托链时,它可以引用一个委托数组

    Delegate类中定义了两个只读的公共实例属性,分别是Target和Method,Target属性返回保存在私有字段_target中的值。如果委托对象包装的是一个静态方法,Target将返回null。Method属性返回对一个System.Reflection.MethodInfo对象的引用,该对象标识了回调方法。实际例子:

                //创建委托对象 new运算符实例化委托
                PerformCalculation myDelegate = new PerformCalculation(Add);
                //调用委托
                myDelegate(100, 100);
    
                Console.WriteLine("Target:{0} Method:{1}",myDelegate .Target,myDelegate.Method);
                Program p = new Program();
    
                myDelegate=p.Division;
                myDelegate(100, 100);
                Console.WriteLine("Target:{0} Method:{1}",myDelegate .Target,myDelegate.Method);

    调用结果:

    委托链

    委托链是由委托对象构成的一个集合。利用委托链,可以调用集合中的委托所包装的全部方法。
    委托链示例见demo,ChainDelegateDemo1、ChainDelegateDemo2 方法。

    • 构造委托链会使用System.Delegate 的Combine静态方法,移除委托使用System.Delegate 的Remove静态方法。C#编译器自动为委托类型的实例重载了+= 和-=操作符。操作符分别调用System.Delegate.Combine和System.Delegate.Remove
    • 当构造委托链时,_invocationList字段会被初始化为引用一个委托对象的数组,这一点也非常重要

    园中的优秀文章

    C# 中的委托和事件

    读<<CLR via C#>>总结(10) 详谈委托

    跟小静学CLR via C#(12)-委托Delegate

  • 相关阅读:
    web ERP前端技术选型
    poj1741 Tree 树的分治
    HDU4694 未AC
    zoj4100 Balanced Number 数位DP
    树的最小表示法 UVA 12489
    2013长沙网赛 I题 Grand Prix
    2013第八场多校
    2013第六场多校
    2013第五场多校
    ZOJ3724 树状数组+离线处理
  • 原文地址:https://www.cnblogs.com/whx1973/p/delegate.html
Copyright © 2020-2023  润新知