【问题标题】:How methods of delegate type are generated internally?委托类型的方法是如何在内部生成的?
【发布时间】:2011-08-22 17:11:57
【问题描述】:

我知道委托类型是从 MulticastDelegate 继承的,而 MulticastDelegate 又是从 Delegate 类继承的。

此外,当我们创建委托实例时,它会创建三个具有相同委托签名的方法(Invoke、BeginInvoke、EndInvoke 和构造函数)。

我无法理解它是如何在内部创建的(具有委托类型签名的方法)?

提前致谢。

【问题讨论】:

  • 它是如何创建的 - 代码由 C# 编译器发出。您还需要了解什么?

标签: c# delegates


【解决方案1】:

如果您查看 Reflector 或 ILSpy 中委托类型的 IL,您会发现它看起来像这样:

.class public sealed System.Action extends System.MulticastDelegate
{
    .method public hidebysig specialname rtspecialname instance void .ctor(object 'object', native int 'method') runtime managed {}

    .method public hidebysig newslot virtual instance void Invoke() runtime managed {}

    .method public hidebysig newslot virtual instance class System.IAsyncResult BeginInvoke(class System.AsyncCallback callback, object 'object') runtime managed {}

    .method public hidebysig newslot virtual instance void EndInvoke(class System.IAsyncResult result) runtime managed {}
}

即构造函数 (.ctor)、InvokeBeginInvoke/EndInvoke 方法。您还会注意到这些方法没有实现(方法主体为空),并标有runtime

runtime 关键字向 CLR 表明此方法需要由 CLR 本身提供的实现。也就是说,委托的实现完全是 CLR 本身内部的魔术。加载委托类型时,CLR 会注意到它派生自 System.Delegate,注意到 runtime 标志,因此在 CLR 内为该特定委托类型创建这些方法的实现。

这些实现实际上是什么样子完全取决于您在其上运行它的 CLR(无论是 .NET 平台、Mono 还是其他),但很可能直接在本机代码中。

当编译器编译委托类型时,它只是创建这些方法存根来匹配 CLR 所期望的模式,然后将其保留。委托的实际工作方式取决于运行时。

【讨论】:

    【解决方案2】:

    例如,我们有一个这样的委托:

    public delegate int BinaryOp(int x, int y);
    

    编译器如何知道如何定义 Invoke()、BeginInvoke() 和 EndInvoke() 方法?

    这是编译器生成的类:

    sealed class BinaryOp : System.MulticastDelegate
    {
    public BinaryOp(object target, uint functionAddress);
    public int Invoke(int x, int y);
    public IAsyncResult BeginInvoke(int x, int y,AsyncCallback cb, object state);
    public int EndInvoke(IAsyncResult result);
    }
    

    首先,注意为 Invoke() 方法定义的参数和返回值 匹配 BinaryOp 委托的定义。

    BeginInvoke() 成员的初始参数(在我们的例子中是两个整数)也基于 BinaryOp 委托;
    但是,BeginInvoke() 将始终提供两个最终参数(类型为 AsyncCallback 和对象),用于促进异步方法调用。

    最后EndInvoke()的返回值和原来的一样 委托声明,并将始终将实现的对象作为唯一参数 IAsyncResult 接口。

    【讨论】:

    • 你的意思是编译器会负责生成带有正确参数的方法?
    • 是的。编译器将查看委托的返回类型和参数,并相应地创建方法。例如如果两个参数where为char类型,则生成的类中的方法将有char类型的参数。
    猜你喜欢
    • 2016-09-08
    • 2010-11-26
    • 1970-01-01
    • 2010-10-20
    • 2022-08-15
    • 2012-05-17
    • 2010-10-03
    • 1970-01-01
    • 2012-02-13
    相关资源
    最近更新 更多