四、共享程序集与强命名程序集

CLR #程序集

CLR via C#漫游者指南(四):共享程序集与强命名程序集

第四章《类型基础》介绍了CLR(公共语言运行时)中的类型系统,包括类型的继承、命名空间、程序集关系,以及运行时对象的内存管理。以下是本章的详细总结,并配以代码示例和图解说明:


1. 所有类型都派生自 System.Object

CLR 要求所有类型最终都继承自 System.Object,这意味着每个类型都至少具备 System.Object 的基本方法,如 ToString()GetHashCode()Equals() 等。

代码示例

class Employee // 隐式继承 System.Object
{
}

class EmployeeExplicit : System.Object // 显式继承 System.Object
{
}

System.Object 提供的方法:

方法 说明
Equals() 判断两个对象是否相等
GetHashCode() 返回对象的哈希值
ToString() 返回对象的字符串表示
GetType() 返回对象的运行时类型

2. 类型转换(Casting)

隐式转换

子类对象可以隐式转换为基类对象,无需额外语法:

Employee e = new Manager(); // Manager 是 Employee 的子类

显式转换

基类对象转换为子类对象时,必须使用 显式转换(可能会失败):

Employee e = new Employee();
Manager m = (Manager)e; // 运行时可能会抛出 InvalidCastException

new操作符

没有和new操作符对应的的delete操作符,没有办法显示释放为对象分配的内存。CLR采用垃圾回收机制自动释放对象内存。

sequenceDiagram participant App as 应用程序代码 participant CLR as 公共语言运行时 (CLR) participant Heap as 托管堆 (Managed Heap) App->>CLR: new Manager() CLR->>CLR: 计算对象所需的内存大小 CLR->>Heap: 在托管堆中分配内存 Heap-->>CLR: 返回对象内存地址 CLR->>CLR: 初始化类型对象指针 & 同步块索引 CLR->>CLR: 调用构造函数 (Constructor) CLR-->>App: 返回对象引用

is 和 as 关键字

  • is:用于检查对象是否为特定类型,返回 truefalse
  • as:尝试转换类型,如果失败,则返回 null,不会抛出异常。
//CLR检查两次对象类型
object o = new Employee();
if (o is Employee) {
    Employee e = (Employee)o;
}

//CLR仅需校验一次对象类型,更优
Employee e2 = o as Employee;
if (e2 != null) {
    // 转换成功
}

3. 命名空间和程序集

命名空间用于组织代码,避免名称冲突。对于编译器,命名空间的作用就是为类型名称附加以句点分割的符号,使命名更长,更可能具有唯一性。例如:

namespace Company.Department
{
    class Employee { }
}

程序集(Assembly)是CLR管理代码的基本单位,类型可以分布在多个程序集。

示例:

using System.IO;
using System.Text;

FileStream fs = new FileStream("test.txt", FileMode.Open);
StringBuilder sb = new StringBuilder();

上面的 using 指令允许在代码中使用简短类型名称,而不需要全限定名,如 System.IO.FileStream


4. 运行时内存管理

运行时对象关系

CLR 维护堆(Heap)和栈(Stack):

  • 栈(Stack):存储方法调用时的局部变量和参数,速度快。
  • 堆(Heap):存储引用类型对象,动态分配,需垃圾回收。

代码示例

void M1() {
    string name = "Joe";
    M2(name);
}

void M2(string s) {
    int length = s.Length;
}

执行流程

  1. M1 方法被调用时,name 变量分配在 上。
  2. M1 调用 M2(name),参数 name 被压入
  3. M2 方法的局部变量 length 也存储在
  4. M2 返回时,栈会释放 length 变量。

图示:

sequenceDiagram participant Stack as 线程栈(Stack) Note over Stack: 调用 M1() 之前 Stack ->> Stack: [Stack 空] Note over Stack: 调用 M1() 之后 Stack ->> Stack: [ name = "Joe" ] Note over Stack: 调用 M2(name) Stack ->> Stack: [ s = "Joe", return 地址 ]

5. 继承和方法调用

CLR 维护 类型对象(Type Object),其中包含类型信息、方法表等。对象存储在 堆(Heap),并指向其对应的类型对象。

同步块索引(Sync Block Index)是什么?

CLR(公共语言运行时)托管堆 中,每个对象都有两个隐藏的头部字段:

  1. 类型对象指针(Type Object Pointer):指向该对象的类型元数据。
  2. 同步块索引(Sync Block Index):用于支持 线程同步(Synchronization) 机制。

同步块索引是 对象头(Object Header) 的一部分,它存储在 对象的内存块之前,用于管理 锁定(Locking)、哈希码(HashCode)、垃圾回收(GC)标记 等信息。

代码示例

class Employee {
    public virtual string GetReport() {
        return "Employee Report";
    }
}

class Manager : Employee {
    public override string GetReport() {
        return "Manager Report";
    }
}

Employee e = new Manager();
Console.WriteLine(e.GetReport()); // 输出 "Manager Report"

执行流程

  • 运行时,e.GetReport() 解析 e 的类型,发现其实际类型为 Manager,调用 Manager.GetReport() 方法。

6. 方法表(Method Table)

每个类型在 CLR 中都有 方法表(Method Table),存储其方法指针:

  • 非虚方法(Non-virtual method):直接调用目标方法。
  • 虚方法(Virtual method):通过 方法表 查找实际类型的方法并执行。

方法调用示例

class Employee {
    public virtual void Work() { Console.WriteLine("Employee working"); }
}

class Manager : Employee {
    public override void Work() { Console.WriteLine("Manager working"); }
}

Employee e = new Manager();
e.Work(); // 调用 Manager.Work()

CLR 运行时会通过 vtable(虚方法表)查找 Manager.Work() 方法,并调用它


7. 类型对象(Type Object)

在 CLR 内部,所有对象都包含一个 类型对象指针,用于指向其类型信息。

对象存储示意图

graph TD; subgraph Heap["堆 (Heap)"] ManagerObj["🟦 Manager 对象"] ManagerType["📄 Manager Type Object"] EmployeeType["📄 Employee Type Object"] end ManagerObj -->|类型对象指针| ManagerType ManagerType -->|继承| EmployeeType ManagerType -->|方法表| Work["🔹 Work() 方法"]

当调用 e.Work() 时:

  1. 解析 e 的类型对象。
  2. 通过 方法表 查找 Work() 方法的实际实现(Manager)。
  3. 调用 Manager.Work()

总结

本章介绍了CLR的 类型系统,包括:

  • 所有类型最终继承 System.Object,并提供 ToString()GetType() 等基本方法。

  • 类型转换(Casting):

    • 隐式转换(安全)
    • 显式转换(可能失败)
    • isas 关键字 进行安全转换
  • 命名空间和程序集 组织代码,避免命名冲突。

  • 运行时内存管理:

    • 栈(Stack) 存储局部变量,自动回收。
    • 堆(Heap) 存储对象,垃圾回收管理。
  • 方法调用:

    • 非虚方法 直接调用。
    • 虚方法 通过 方法表(Method Table) 查找实际实现。
  • CLR 内部对象存储:

    • 类型对象(Type Object) 存储方法表、静态字段等。
    • 对象包含类型对象指针,指向其类型信息。

posted @ 2025-08-26 10:06  世纪末の魔术师  阅读(12)  评论(0)    收藏  举报