【问题标题】:In .NET, what is the internal implementation of a delegate?在 .NET 中,委托的内部实现是什么?
【发布时间】:2021-04-28 21:10:53
【问题描述】:

我知道委托的声明是这样的:

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

但是,肯定还有更多事情要做。委托的目的是提供一个指向方法的指针,并在委托中封装对方法的引用。

这个引用保存在什么样的结构中(在委托内部)?我也知道您可以在委托中封装对多个方法的引用。这是否意味着委托中有一个数组来保存这些?

此外,委托中定义了哪些方法等。当您使用简洁声明委托时真正发生了什么:

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

?

编辑: 一些澄清。当您声明一个委托时,编译器会自动为您创建一个继承自 System.MulticastDelegate 的 密封 类。如果您使用 ildasm 查看您的程序集,您可以看到这一点。这整齐。基本上,通过一个语句,您将在编译时为您生成一个全新的类,它具有您需要的所有功能。

【问题讨论】:

  • 你可以用反射器检查很多。缺少一些部分,因为它们需要运行时魔法。但是您仍然会看到单个和多播代表的大部分内容。

标签: c# .net delegates implementation internal


【解决方案1】:

所有委托都继承自 System.Delegate 类型,该类型拥有 TargetMethod。更准确地说,它们继承自 System.MultiCastDelegate,后者继承自 System.Delegate

【讨论】:

  • 谢谢!这几乎正​​是我想要的。我为自己没有找到那个而感到愚蠢。我似乎无法找到委托如何持有多个引用。它有一个目标和一个方法,但这些看起来不像集合。 . .我在这里错过了什么?
  • @Richard DesLonde,您缺少System.MulticastDelegate,这是所有代表继承的。为了更清楚,我更新了我的答案。
  • 他们没有实现——他们继承了。
  • 谢谢,所以在内部,多播委托有一个委托链接列表? @Ani:感谢您的更正。这是有道理的。
  • @richard 他们可能在框架的第一个版本中使用了链表,但当前版本使用简单的不可变委托数组,每次您向多播委托添加或删除委托时都会丢弃该数组.
【解决方案2】:

在内部它是一个引用类型,非常类似于一个类。抄写下来是这样的:

public /* delegate */ class PerformCalculation : MulticastDelegate {
    public PerformCalculation(object target, IntPtr method) {}
    public virtual void Invoke(int x, int y) {}
    public virtual IAsyncResult BeginInvoke(int x, int y, AsyncCallback callback, object state) {}
    public virtual void EndInvoke(IAsyncResult result) {}
}

我将这些成员的实现留空,它们实际上映射到 CLR 中的代码。编译器根据委托声明的签名动态生成方法签名。注意 x 和 y 参数。 JIT 编译器帮助调用构造函数,使用 += 或 -= 语法,它知道委托目标方法的内存地址。编译器自动生成 target 参数值,具体取决于目标方法是否为静态。这两个参数映射到 (Multicast)Delegate.Target 和 Method 属性。实际的基类实例可以是 Delegate 或 MulticastDelegate,具体取决于订阅了多少个目标。

这里有很多秘方。

【讨论】:

  • 好东西。你能解释一下委托调用所涉及的开销吗?特别是与虚拟方法调用相比。
  • 很难说,调试器对于调试这段代码是非常胡思乱想。肯定有开销,它不是一个简单的虚拟方法调用。 Afaict,它调用 jitted Invoke() 方法,然后间接调用一个 thunk 按摩堆栈帧并调用正确的调用程序,具体取决于它是 Delegate 还是 MulticastDelegate。后者需要迭代调用列表。当我分析它时它非常便宜(纳秒),但肯定不如方法调用便宜。
  • 谢谢汉斯。内部的东西非常有用和有趣。
  • 我前段时间看到了一些关于这个的基准。然而,我再也找不到它了,不管你接受与否,开销小得惊人。
  • 这确实应该提到TargetMethod 属性;它们对于理解“委托实例”的构成至关重要,IMO。
猜你喜欢
  • 1970-01-01
  • 2013-12-30
  • 1970-01-01
  • 2021-03-23
  • 1970-01-01
  • 2012-03-23
  • 1970-01-01
相关资源
最近更新 更多