深入理解.net运行时方法表

在.net运行时,每一个类型在创建第一个实例,或者静态成员被第一次访问,或者被反射创建时,就会创建一个与该类型关联的方法表:

基本结构大概如下:

复制代码
+--------------------------+
|      Method Table        |
+--------------------------+
|   Virtual Method #1 ptr  |
|   Virtual Method #2 ptr  |
|   ...                    |
|   Non-virtual Method ptr |
+--------------------------+
|   Type Information       |
|   (Size, Base Type ptr,  |
|    ... other info)       |
+--------------------------+

其中重点分为两部分,方法表与描述类型的元数据。

方法表中的每一项包含了方法的标识信息与指针ptr,指针指向了方法体在内存中的实际地址。

方法表中的项又分为两类:虚方法与实方法,两者的区别体现在方法表的继承上。

举例子,我创建了如下两个类,他们存在继承关系:

cs 复制代码
public class BaseClass
{
    public virtual void MethodA()
    {
        Console.WriteLine("BaseClass.MethodA");
    }

    public virtual void MethodB()
    {
        Console.WriteLine("BaseClass.MethodB");
    }
}

public class DerivedClass : BaseClass
{
    public override void MethodB()
    {
        Console.WriteLine("DerivedClass.MethodB");
    }

    public virtual void MethodC()
    {
        Console.WriteLine("DerivedClass.MethodC");
    }
}

两个类型的方法表如下:

基类BaseClass的方法表:

cs 复制代码
+------------------------+
|      Method Table      |
+------------------------+
|   Virtual Method #1    | 函数指针指向  -->  BaseClass.MethodA
|   Virtual Method #2    | 函数指针指向  -->  BaseClass.MethodB
+------------------------+

子类DerivedClass的方法表:

cs 复制代码
子类继承了基类的方法表项MethodA与MethodB
+------------------------+
|      Method Table      |
+------------------------+
|   Virtual Method #1    | 未重写,所以依旧指向  -->  BaseClass.MethodA
|   Virtual Method #2    | 重写了,所以指向  -->  DerivedClass.MethodB
|   Virtual Method #3    |   -->  DerivedClass.MethodC
+------------------------+

基于这种机制,就实现了多态,在创建实例时,实例的"对象头"中包含了指向自身类型所对应的方法表的指针,基于此,找到方法表,再根据方法标识找到对应的方法表项,从而就自然而然找到了指向方法体的指针。

实例的"对象头"大概结构如下:

cs 复制代码
+----------------------+
|      对象头           |
+----------------------+
|   类型指针            |   -->  指向方法表的指针
|   同步锁信息          |   -->  用于同步的信息
|   标记信息            |   -->  垃圾回收标记信息
|   ...其他元信息...    |
+----------------------+
|      对象数据         |   -->  实际存储对象数据的部分
+----------------------+

当将"实例"作为参数传递时,所传递的是"实例的引用",说人话就是传递指向上述结构中"对象头"部分起始位置的指针,找到了"对象头",运行时自然也就能够知道该对象的类型信息了,从而实现了高级的语言特性,如多态性、垃圾回收等。调用虚方法、判断对象的实际类型等操作都依赖于这种引用机制,使得对象在运行时能够灵活地适应不同的上下文。

抽象类

抽象类的方法表(Method Table)与普通类的方法表类似,不过抽象类的方法表中可能包含抽象方法。抽象方法是一种只有方法签名而没有具体实现的方法,需要在派生类中进行实现。

让我们通过一个简单的例子来理解抽象类的方法表。假设有如下的抽象类:

cs 复制代码
public abstract class MyBaseClass
{
    public abstract void AbstractMethod();

    public void ConcreteMethod()
    {
        Console.WriteLine("Concrete method in MyBaseClass");
    }
}

对应的抽象类方法表可能类似于以下结构:

cs 复制代码
+------------------------+
|      Method Table      |
+------------------------+
|   Virtual Method #1    |   -->  MyBaseClass.AbstractMethod
|   Virtual Method #2    |   -->  MyBaseClass.ConcreteMethod
+------------------------+

在这个示例中:

  • AbstractMethod 是一个抽象方法,它在抽象类中只有方法签名而没有具体实现。
  • ConcreteMethod 是一个普通的方法,它有具体的实现。

抽象方法在方法表中会被表示为虚方法(Virtual Method),因为它们需要在派生类中进行具体的实现。派生类中实现的具体方法会在其自己的方法表中添加相应的条目。

当一个派生类继承了抽象类并实现了抽象方法时,它的方法表可能会变成类似这样:

cs 复制代码
+------------------------+
|      Method Table      |
+------------------------+
|   Virtual Method #1    |   -->  DerivedClass.AbstractMethod (实现抽象方法)
|   Virtual Method #2    |   -->  MyBaseClass.ConcreteMethod
+------------------------+

这样,抽象类的方法表中包含了抽象方法和具体方法的信息,而派生类的方法表中则包含了实现的具体方法的信息。这种继承关系和方法表的组织方式使得多态性在抽象类和派生类中得以实现。

接口Interface

接口(Interface)在.NET中也有与之相关的方法表(Method Table)的概念,不过与类的方法表有一些区别。接口中的方法表用于存储接口中定义的方法的签名,而不包含具体的实现。

让我们通过一个简单的例子来理解接口的方法表。假设有如下的接口:

cs 复制代码
public interface IMyInterface
{
    void InterfaceMethod();
}

对应的接口方法表可能类似于以下结构:

cs 复制代码
+------------------------+
|      Method Table      |
+------------------------+
|   Virtual Method #1    |   -->  IMyInterface.InterfaceMethod
+------------------------+

在这个示例中:

  • InterfaceMethod 是接口中定义的方法,它只有方法签名而没有具体实现。

当一个类实现了接口时,它会实现接口中定义的方法,并且在该类的方法表中会包含接口方法的实现。例如,如果有如下的类:

cs 复制代码
public class MyClass : IMyInterface
{
    public void InterfaceMethod()
    {
        Console.WriteLine("InterfaceMethod implementation in MyClass");
    }
}

MyClass 的方法表可能会变成类似这样:

cs 复制代码
+------------------------+
|      Method Table      |
+------------------------+
|   Virtual Method #1    |   -->  MyClass.InterfaceMethod (实现接口方法)
+------------------------+

这样,接口的方法表记录了接口方法的签名,而实现了接口的类的方法表包含了实际的方法实现。这种方式支持了类对多个接口的实现,实现了接口隐式地引入了多态性,允许通过接口引用调用具体实现的方法。

相关推荐
自学AI的鲨鱼儿30 分钟前
ubuntu22.04安装gvm管理go
开发语言·后端·golang
旭意1 小时前
C++微基础备战蓝桥杯之数组篇10.1
开发语言·c++·蓝桥杯
MediaTea1 小时前
Python:匿名函数 lambda
开发语言·python
R-G-B1 小时前
【06】C#入门到精通——C# 多个 .cs文件项目 同一项目下添加多个 .cs文件
开发语言·c#·c# 多个 .cs文件项目
数据知道2 小时前
Go基础:正则表达式 regexp 库详解
开发语言·mysql·golang·正则表达式·go语言
小蒜学长2 小时前
jsp基于JavaWeb的原色蛋糕商城的设计与实现(代码+数据库+LW)
java·开发语言·数据库·spring boot·后端
zhangfeng11332 小时前
亲测可用,R语言 ggplot2 箱线图线条控制参数详解,箱线图离散数值控制
开发语言·python·r语言·生物信息
yzx9910132 小时前
国庆科技感祝福:Python 粒子国旗动画
开发语言·人工智能·python
迪丽热爱2 小时前
【练】C程序设计-01程序设计和C语言
c语言·开发语言
扶尔魔ocy2 小时前
【QT常用技术讲解】opencv实现摄像头图像检测并裁剪物体
开发语言·qt·opencv