• 漫话CLR ---- 委托


      委托,delegate,说白了也就是个语法糖.没有他我们可以写程序,有了他我们可以写出更好的程序.

    delegate void Feedback(int value);

      方法签名之前前加上 delegate 关键字,我们就定义了一个最简单的委托.但,事实上编译器为我们做了另一件事:创建委托类.人肉解压缩一下:

    //这里就是整个委托最为核心的内容,委托 = 封装了的类 + Invoke方法
    class
    Feedback : System.MulticastDelegate { public Feedback(Object obj,IntPtr method); public virtual void Invoke(int value); public virtual IAsyncResult BeginInvoke(int value, AsyncCallback callback,Object obj); public virtual void EndInvoke(IAsyncResult result); }

      注意生成的 Invoke 方法,这个方法的和原来使用 delegate 创建的 方法签名 原型是一致的. 可以说 委托 并不是一种新的操作或者行为之类的.他只是简化了以前我们需要通过手动编码的复杂程度.原来需要编写一个类来进行操作的步骤,现在由编译器帮我们完成了,这个就是语法糖,这个就是委托.

      多播委托,或者委托链,这个是什么,其实就是在 编译器 创建的 Feedback 类中加入的一个数组,如果有多个委托方法连接到一个委托上,执行的时候就相当于 Foreach 这个数组,每个方法 执行一下他的 Invoke. 这个数组放在哪里,其实就在继承的 System.MulticastDelegate 中,他有一个私有成员变量, _invocationList,这是个数组,每次增加或者删除一个委托就是在进行维护这个 委托 数组的操作.

    //多播委托的 Invoke 方法执行类似下面的伪代码
    public void Invoke(int value)
    {
        Delegate[] delegateSet = _invocationList as Delegate[];
        if(delegateSet != null)
        {
            // 委托数组不为null,证明是一个委托链
            foreach(Feedback d in delegateSet)
                d(value);    //或者 d.Invoke(value)
        }
        else
        {
            //不为空,则调用原始的回调方法
            _methodPtr.Invoke(_target, value);
            //逻辑近似实际代码,但实际发生的事情 C# 是表示不出来的
        }
    }

      另:可以通过 GetInvocationList()方法来获取多播委托绑定的成员.

      泛型委托,就是系统中的 Action 和 Func,你可以在MSCorLib.dll 和 System.Core.dll 中找到他们,建议使用这些委托类型而不是定义更多的类型.

    public delegate void Action();
    public delegate void Action<T>(T obj);
    public delegate void Action<T1, T2>(T1 arg1, T2 arg2);
    public delegate void Action<T1, T2, T3>(T1 arg1, T2 arg2,T3 arg3);
    ...
    
    public delegate TResult Func<TResult>();
    public delegate TResult Func<T,TResult>(T obj);
    public delegate TResult Func<T1, T2, TResult>(T1 arg1, T2 arg2);
    public delegate TResult Func<T1, T2, T3, TResult>(T1 arg1, T2 arg2,T3 arg3);
    ...

      C#为委托提供了很多简化的语法,比如委托连的 += 和 -= 操作实际上是Delegate类中 Combine 和 Remove 方法的简化, lambda 表达式实际上是匿名方法的一种简化,匿名方法实际上在编译的时候由编译器自己生成了一个方法 ... 这些简化很有效的提高了我们的开发效率,但也让一部分开发者感到迷茫.就如一句话所说:知道真相使你自由.明白其中的原理也会让你更合理的使用这些语法糖,而不至于迷失在糖罐中.

      简化语法1: 不需要构造委托对象

    button1.Click += new EventHandler(button1_Click);
    //可以简化为
    button1.Click += button1_Click;

      实际上,第二种情况下在编译的时候会由编译器自行加上包装器.

      简化语法2: 不需要定义回调方法

      可以理解为lambda 表达式和匿名函数,编译的时候也是由编译器"解压"为正常的方法和类.

      简化语法3: 局部变量不需要手动包装到类中即可传给回调方法

    Jeffrey Richter的一个小规则:如果需要在回调的方法中包含3行以上的代码,就不使用 lambda表达式.

      委托和反射,两个重要的方法:

    Delegate del = Delegate.CreateDelegate(...);
    del.DynamicInvoke(...)  //伪代码,不多解释,只是说明方法名和所在的位置
  • 相关阅读:
    内存映射函数remap_pfn_range学习——代码分析(3)
    内存映射函数remap_pfn_range学习——示例分析(2)
    内存映射函数remap_pfn_range学习——示例分析(1)
    在busybox里使用ulimit命令
    unlocked_ioctl和compat_ioctl
    使用cat读取和echo写内核文件节点的一些问题
    如何成为强大的程序员?
    如何实现“秒杀”系统
    关于博客园代码样式的调整
    Consuming a RESTful Web Service
  • 原文地址:https://www.cnblogs.com/woodywu/p/3216677.html
Copyright © 2020-2023  润新知