如何在C#中实现reflection?
我很好奇Type.GetType()
的实现位置,所以我看了一下程序集,注意到Type.GetType()
调用了base.GetType()
而且由于Type
inheritance自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实现细节( MethodInfo
, Type
等)可能是C#。
它可能不会直接回答你的问题。 但是,这里有一个关于托管代码如何了解类型的一些概述。
-
无论何时编译代码,编译器都会分析/解析源文件并收集它遇到的信息。 例如,看看下面的课程。
class A { public int Prop1 {get; private set;} protected bool Met2(float input) {return true;} }
编译器可以看到这是一个有两个成员的内部类。 成员1是具有私有setter的int类型的属性。 成员2是名为Met2的受保护方法,类型为boolean,采用浮点输入(输入名称为’input’)。 所以,它拥有所有这些信息。
-
它将此信息存储在程序集中。 有几张桌子。 例如,类(类型)都留在一个表中,方法存在于另一个表中。 想想在SQL表格中,尽管它们肯定不是。
-
当用户(开发人员)想知道有关类型的信息时,它调用GetType方法。 此方法依赖于对象隐藏字段 – 类型对象指针。 该对象基本上是指向类表的指针。 每个类表都有一个指向方法表中第一个方法的指针。 每个方法记录都有一个指向参数表中第一个参数的指针。
PS:这种机制是使.NET程序集更安全的关键。 您无法替换指向方法的指针。 它将打破集合的签名。
JIT编译也非常依赖于这些表
正如@GlennFerrieLive所指出的,对GetType的调用是一个InternalCall
,这意味着实现是在CLR本身内,而不是在任何BCL中。
我的理解是内部CLR方法从this
指针获取运行时类型信息,它基本上等于类型的名称。 然后,它从所有已加载程序集中的元数据中查找完整的类型信息(可能是在当前的appdomain中),这使得reflection相当昂贵。 元数据区域基本上是程序集中存在的所有类型和成员的数据库,它从此数据构造Type
或Method|Property|FieldInfo
的实例。