美文网首页
寻求真相 — C#的delegate底层原理

寻求真相 — C#的delegate底层原理

作者: SunnyDecember | 来源:发表于2019-11-16 01:20 被阅读0次

  先来看一段代码:

class AClass
{
    public delegate int MyDelegate(string str);
    public MyDelegate myDelegate;
}

class Program
{
    static void Main(string[] args)
    {
        int LocalFunction(string a)
        {
            return 789;
        }

        AClass aClass = new AClass();
        aClass.myDelegate += t => { return 123; };
        aClass.myDelegate -= t => { return 456; };
        aClass.myDelegate -= LocalFunction;
        aClass.myDelegate += LocalFunction;

        aClass.myDelegate = new AClass.MyDelegate(LocalFunction);
        aClass.myDelegate?.Invoke("");
    }
}

  编译生成exe可执行文件,并反编译IL得到代码如下:


反编译IL得到的结果(图一)

  接着再看AClass是什么样子的:


AClass(图二)

  根据图上可知,委托MyDelegate最终会被生成为一个类,并且继承于MulticastDelegate,MulticastDelegate继承Delegate,而myDelegate则是它的实例。当我们对委托+= 操作时候,其实是调用了Delegate.Combine()函数,如上图的匿名函数,会被传进Combine中,并返回一个新的Delegate对象给myDelegate。-=操作会调用Remove函数。不知道你注意到没有,当我们写一个匿名函数传递给委托时候,会被生成一个函数,例如图一的b__0_1和b__0_2,也就是说每次绑定的匿名函数都会被生成一个带名字的函数,哪怕你写的匿名函数一模一样,编译后都不是同一个东西。但如果不是匿名函数,像LocalFunction,委托的+=和-=都是对同一个函数操作。

  我们不妨再看看源码Delegate.Combine()怎么玩转的:

public static Delegate Combine(Delegate a, Delegate b)
{
    if (a == null)
    {
        return b;
    }
    return a.CombineImpl(b);
}

protected virtual Delegate CombineImpl(Delegate d)
{
    throw new MulticastNotSupportedException(Environment.GetResourceString("Multicast_Combine"));
}

  CombineImpl是虚函数,会调用带子类MulticastDelegate.CombineImpl(),代码太多,只贴一部分:

protected sealed override Delegate CombineImpl(Delegate follow)
{
    if (follow == null)
    {
        return this;
    }
    if (!Delegate.InternalEqualTypes(this, follow))
    {
        throw new ArgumentException(Environment.GetResourceString("Arg_DlgtTypeMis"));
    }
    MulticastDelegate multicastDelegate = (MulticastDelegate)follow;
    int num = 1;
    object[] array = multicastDelegate._invocationList as object[];
    if (array != null)
    {
        num = (int)multicastDelegate._invocationCount;
    }
    object[] array2 = this._invocationList as object[];
    int num2;
    object[] array3;
    if (array2 == null)
    {
        num2 = 1 + num;
        array3 = new object[num2];
        array3[0] = this;
        if (array == null)
        {
            array3[1] = multicastDelegate;
        }
        else
        {
            for (int i = 0; i < num; i++)
            {
                array3[1 + i] = array[i];
            }
        }
        return this.NewMulticastDelegate(array3, num2);
    }

看到这里大概都能猜到了,每个委托类无非就是包含了一个数组,数组记录了多个Delegate,当我们编写+=,把回调函数的包装类MulticastDelegate的数据合并到另一个MulticastDelegate中,一旦执行invoke,便调用所有的回调函数。

Author : SunnyDecember
Date : 2019.11.16
原文

相关文章

  • 寻求真相 — C#的delegate底层原理

      先来看一段代码:   编译生成exe可执行文件,并反编译IL得到代码如下:   接着再看AClass是什么样子...

  • 寻求真相 — new的底层原理.

    我们带着问题去探讨new之后的底层原理. new之后的流程是什么内存如何被读写地址如何产生地址如何表示 1.吐槽 ...

  • 寻求真相 — Git的底层原理

      先说结论,再展开分析。  git的文件分为四种类型,分别是:blob,tree,commit,tag。  bl...

  • C#委托

    C#中的delegate 在c#中,event与delegate是两个非常重要的概念。因为在Windows应用程序...

  • C# 委托

    C#委托 C#中的委托(Delegate)类似于C或C++中函数的指针。委托(Delegate)是存有对某个方法的...

  • C# Unity 委托

    文档:Delegat 一.解释下delegate: 我们平时使用的delegate,是关键字 C#编译器,它先自动...

  • C#委托Delegate和事件Event实战应用

    一、委托的概念 C# 中的委托(Delegate)类似于 C 或 C++ 中函数的指针。委托(Delegate)是...

  • C# delegate

    C# 中的 Delegate 类似于 C++ 中函数的指针。所有的委托Delegate都派生自 System.De...

  • C# 委托(Delegate)

    C# 中的委托(Delegate)类似于 C 或 C++ 中的函数指针。委托(Delegate) 是存有对某个方法...

  • 19-委托

    C# 中的委托(Delegate)类似于 C 或 C++ 中函数的指针。 委托(Delegate) 是存有对某个方...

网友评论

      本文标题:寻求真相 — C#的delegate底层原理

      本文链接:https://www.haomeiwen.com/subject/omdeictx.html