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

原文地址:https://www.cnblogs.com/whx1973/p/delegate.html