C#中reflection、runtime type等概念关联及相关问题咨询
解答
认知修正
你之前对反射、程序集、元数据的基础理解是正确的,仅存在一个核心认知偏差:元数据存储的是你代码中定义的所有类型的完整信息,并非只存储变量的编译时静态类型。运行时类型本身就是你编码阶段就定义好的类型,其元数据在编译时就已经写入程序集,编译阶段不确定的只是「某个变量会指向什么类型的实例」,而非「类型本身的定义」。
问题逐个澄清
- 问题1:通过反射获取对象的类型时,得到的是runtime type还是static type?
答:得到的是运行时类型(runtime type)。反射操作的是内存中实际存在的对象的真实类型,和声明变量时使用的静态类型无关。 - 问题2:如果可以从元数据中获取runtime type,其实现机制是怎样的?
答:每个.NET对象的内存头部都存在一个类型对象指针,该指针指向该类型对应的System.Type实例(也叫类型对象)。System.Type实例是CLR在该类型第一次被使用时,从程序集元数据中加载生成的,只要是你代码中定义过的类型,元数据中都包含完整信息,CLR都会生成对应的Type实例,反射读取的就是该实例的信息,对应对象的真实运行时类型。 - 问题3:我是否可以直接使用
GetType()完成该操作?
答:可以。object.GetType()是.NET提供的最基础的运行时类型获取方法,它的底层逻辑就是读取对象头部的类型对象指针,返回对应的Type实例,本身就属于反射基础设施的组成部分,你给出的示例代码正是这个方法的典型使用场景。 - 问题4:assembly是编译后的代码,编译阶段尚未确定runtime type,运行时如何从assembly的元数据中提取到runtime type?
答:你混淆了「变量的静态类型」和「类型本身的定义」两个概念:- 编译阶段不确定的是某个变量最终会指向哪个类型的实例,但你代码中定义的所有类型(比如示例中的
Base和Derived)的完整结构、成员信息,在编译时就已经全部写入程序集元数据,不存在普通类型的定义到运行时才生成的情况(动态emit生成的类型除外)。 - 运行时执行
new Derived()时,CLR会先从元数据中读取Derived的类型定义,创建实例的同时给实例头部绑定指向Derived对应的Type实例的指针。后续不管你用什么静态类型的变量指向该实例,调用GetType()时都是读取实例自身携带的类型指针,和变量的静态类型没有关系。
- 编译阶段不确定的是某个变量最终会指向哪个类型的实例,但你代码中定义的所有类型(比如示例中的
示例代码逻辑说明
你给出的示例:
Base b = new Derived(); Console.WriteLine(b.GetType());
输出Derived的核心逻辑就是上面提到的:GetType()读取的是实例自身的类型信息,不是变量b的静态类型Base。你认为「元数据仅存储编译阶段确定的类型信息」是正确的,但Derived本身就是你编译阶段就定义好的类型,它的元数据在编译时就已经存在于程序集中,只是编译时不知道变量b会指向Derived的实例而已,不存在运行时从元数据找不到Derived类型的问题。
内容的提问来源于stack exchange,提问作者Calculon
相关产品推荐
相关产品推荐

