如何在C#中实现reflection?

我很好奇Type.GetType()的实现位置,所以我看了一下程序集,注意到Type.GetType()调用了base.GetType()而且由于Typeinheritance自MemberInfo我看了一下它被定义为_MemberInfo.GetType()返回this.GetType() 。 由于我无法找到显示C#如何获取类型信息的实际代码,我想知道:

CLR如何在运行时从对象获取Type和MemberInfo?

.NET Framework 2.0的ACTUAL源可在此处获取(用于教育目的): http : //www.microsoft.com/en-us/download/details.aspx?id = 4917

这是C#语言实现。 您可以使用7zip解压缩它。 你会在这里找到reflection命名空间(相对):

\ sscli20 \ CLR \ SRC \ BCL \ SYSTEM \reflection

我正在挖掘您所询问的具体实施,但这是一个良好的开端。

更新:对不起,但我认为这是一个死胡同。 Type.GetType()调用来自System.Object的基本实现。 如果检查该代码文件( .\sscli20\clr\src\bcl\system\object.cs ),您会发现该方法是extern (参见下面的代码)。 进一步的检查可以揭示实施,但它不在BCL。 我怀疑它将在某个地方使用C ++代码。

 // Returns a Type object which represent this object instance. // [MethodImplAttribute(MethodImplOptions.InternalCall)] public extern Type GetType(); 

更新(再次):我深入挖掘并在CLR虚拟机本身的实现中找到答案。 (它在C ++中)。

第一块拼图在这里:

\ sscli20 \ CLR \ SRC \虚拟机\ ecall.cpp

在这里,我们看到将外部调用映射到C ++函数的代码。

 FCFuncStart(gObjectFuncs) FCIntrinsic("GetType", ObjectNative::GetClass, CORINFO_INTRINSIC_Object_GetType) FCFuncElement("InternalGetHashCode", ObjectNative::GetHashCode) FCFuncElement("InternalEquals", ObjectNative::Equals) FCFuncElement("MemberwiseClone", ObjectNative::Clone) FCFuncEnd() 

现在,我们需要找到ObjectNative::GetClass …这里是:

\ sscli20 \ CLR \ SRC \虚拟机\ comobject.cpp

这是GetType的实现:

  FCIMPL1(Object*, ObjectNative::GetClass, Object* pThis) { CONTRACTL { THROWS; SO_TOLERANT; DISABLED(GC_TRIGGERS); // FCallCheck calls ForbidenGC now INJECT_FAULT(FCThrow(kOutOfMemoryException);); SO_TOLERANT; MODE_COOPERATIVE; } CONTRACTL_END; OBJECTREF objRef = ObjectToOBJECTREF(pThis); OBJECTREF refType = NULL; TypeHandle typeHandle = TypeHandle(); if (objRef == NULL) FCThrow(kNullReferenceException); typeHandle = objRef->GetTypeHandle(); if (typeHandle.IsUnsharedMT()) refType = typeHandle.AsMethodTable()->GetManagedClassObjectIfExists(); else refType = typeHandle.GetManagedClassObjectIfExists(); if (refType != NULL) return OBJECTREFToObject(refType); HELPER_METHOD_FRAME_BEGIN_RET_ATTRIB_2(Frame::FRAME_ATTR_RETURNOBJ, objRef, refType); if (!objRef->IsThunking()) refType = typeHandle.GetManagedClassObject(); else refType = CRemotingServices::GetClass(objRef); HELPER_METHOD_FRAME_END(); return OBJECTREFToObject(refType); } FCIMPLEND 

最后一点, GetTypeHandle的实现以及其他一些支持函数可以在这里找到:

\ sscli20 \ CLR \ SRC \虚拟机\ object.cpp

reflection的最重要部分是作为CLI本身的一部分实现的。 因此,您可以查看MS CLI参考源(也称为“Rotor”)或单声道源 。 但是:它主要是C / C ++。 公共API实现细节( MethodInfoType等)可能是C#。

它可能不会直接回答你的问题。 但是,这里有一个关于托管代码如何了解类型的一些概述。

  1. 无论何时编译代码,编译器都会分析/解析源文件并收集它遇到的信息。 例如,看看下面的课程。

     class A { public int Prop1 {get; private set;} protected bool Met2(float input) {return true;} } 

    编译器可以看到这是一个有两个成员的内部类。 成员1是具有私有setter的int类型的属性。 成员2是名为Met2的受保护方法,类型为boolean,采用浮点输入(输入名称为’input’)。 所以,它拥有所有这些信息。

  2. 它将此信息存储在程序集中。 有几张桌子。 例如,类(类型)都留在一个表中,方法存在于另一个表中。 想想在SQL表格中,尽管它们肯定不是。

  3. 当用户(开发人员)想知道有关类型的信息时,它调用GetType方法。 此方法依赖于对象隐藏字段 – 类型对象指针。 该对象基本上是指向类表的指针。 每个类表都有一个指向方法表中第一个方法的指针。 每个方法记录都有一个指向参数表中第一个参数的指针。

PS:这种机制是使.NET程序集更安全的关键。 您无法替换指向方法的指针。 它将打破集合的签名。

JIT编译也非常依赖于这些表

正如@GlennFerrieLive所指出的,对GetType的调用是一个InternalCall ,这意味着实现是在CLR本身内,而不是在任何BCL中。

我的理解是内部CLR方法从this指针获取运行时类型信息,它基本上等于类型的名称。 然后,它从所有已加载程序集中的元数据中查找完整的类型信息(可能是在当前的appdomain中),这使得reflection相当昂贵。 元数据区域基本上是程序集中存在的所有类型和成员的数据库,它从此数据构造TypeMethod|Property|FieldInfo的实例。