zoukankan      html  css  js  c++  java
  • 漫话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(...)  //伪代码,不多解释,只是说明方法名和所在的位置
  • 相关阅读:
    494 Target Sum 目标和
    493 Reverse Pairs 翻转对
    492 Construct the Rectangle 构建矩形
    491 Increasing Subsequences 递增子序列
    488 Zuma Game 祖玛游戏
    486 Predict the Winner 预测赢家
    485 Max Consecutive Ones 最大连续1的个数
    483 Smallest Good Base
    Django Form组件
    Django Auth组件
  • 原文地址:https://www.cnblogs.com/woodywu/p/3216677.html
Copyright © 2011-2022 走看看