我对Type.GetType()
的实施位置感到好奇,所以我看了一下程序集并注意到Type.GetType()
次调用base.GetType()
,因为Type
继承自MemberInfo
我看一下它被定义为_MemberInfo.GetType()
,返回this.GetType()
。由于我无法找到显示C#如何获取类型信息的实际代码,我想知道:
CLR如何在运行时从对象中获取Type和MemberInfo?
答案 0 :(得分:15)
.NET Framework 2.0的ACTUAL源可在互联网上找到(用于教育目的):http://www.microsoft.com/en-us/download/details.aspx?id=4917
这是C#语言实现。您可以使用7zip解压缩它。你会在这里(相对)找到反射命名空间:
\ sscli20 \ CLR \ SRC \ BCL \ SYSTEM \反射
我正在挖掘您所询问的具体实施,但这是一个良好的开端。
更新:抱歉,我认为这是一个死胡同。 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();
UPDATE(AGAIN):我深入挖掘并在CLR虚拟机本身的实现中找到答案。 (它在C ++中)。
第一块拼图就在这里:
\ sscli20 \ CLR \ SRC \ VM \ 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 \ VM \ 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 \ VM \ object.cpp
答案 1 :(得分:7)
反射的最重要部分是作为CLI本身的一部分实现的。因此,您可以查看MS CLI reference source (aka "Rotor")或mono source。但是:它主要是C / C ++。公共API实现详细信息(MethodInfo
,Type
等)可能是C#。
答案 2 :(得分:5)
它可能不会直接回答你的问题。但是,这里有一个关于托管代码如何了解类型的一些概述。
无论何时编译代码,编译器都会分析/解析源文件并收集它遇到的信息。例如,看看下面的课程。
class A
{
public int Prop1 {get; private set;}
protected bool Met2(float input) {return true;}
}
编译器可以看到这是一个有两个成员的内部类。成员1是具有私有setter的int类型的属性。成员2是名为Met2的受保护方法,类型为boolean,采用浮点输入(输入名称为'input')。所以,它拥有所有这些信息。
它将此信息存储在程序集中。有几张桌子。例如,类(类型)都留在一个表中,方法存在于另一个表中。想想在SQL表格中,尽管它们肯定不是。
当用户(开发人员)想知道有关类型的信息时,它会调用GetType方法。此方法依赖于对象隐藏字段 - 类型对象指针。该对象基本上是一个指向类表的指针。每个类表都有一个指向方法表中第一个方法的指针。每个方法记录都有一个指向参数表中第一个参数的指针。
JIT编译在很大程度上依赖于这些表
答案 3 :(得分:2)
正如@GlennFerrieLive所指出的,对GetType的调用是InternalCall
,这意味着实现在CLR本身内,而不是在任何BCL中。
我的理解是内部CLR方法从this
指针获取运行时类型信息,该指针基本上等于类型的名称。然后,它会从所有已加载程序集中的元数据中查找完整的类型信息(可能是在当前的appdomain中),这使得反射相当昂贵。元数据区域基本上是程序集中存在的所有类型和成员的数据库,它从此数据构造Type
或Method|Property|FieldInfo
的实例。