我对在哪里Type.GetType()
实现感到好奇,所以我看了一下程序集并注意到Type.GetType()
调用base.GetType()
,因为Type
继承自我MemberInfo
看了一下,它被定义为_MemberInfo.GetType()
which 返回this.GetType()
。由于我找不到显示 C# 如何获取类型信息的实际代码,我想知道:
CLR 如何在运行时从对象中获取 Type 和 MemberInfo?
.NET Framework 2.0 的实际源代码可在 Internet 上获得(用于教育目的):http: //www.microsoft.com/en-us/download/details.aspx?id=4917
这是 C# 语言实现。您可以使用 7zip 解压缩它。您将在此处(相对)找到反射命名空间:
.\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\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
反射的最重要部分是作为 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;}
}
编译器可以看到这是一个有两个成员的内部类。成员一是具有私有设置器的 int 类型的属性。成员 2 是一个受保护的方法,名称为 Met2,类型为布尔值,采用浮点输入(输入名称为“输入”)。因此,它拥有所有这些信息。
它将这些信息存储在程序集中。有几张桌子。例如,类(类型)都留在一个表中,方法存在于另一个表中。考虑一下 SQL 表,尽管它们绝对不是。
当用户(开发人员)想要了解有关类型的信息时,它会调用 GetType 方法。此方法依赖于对象隐藏字段 - 类型对象指针。这个对象基本上是一个指向类表的指针。每个类表都有一个指向方法表中第一个方法的指针。每个方法记录都有一个指向参数表中第一个参数的指针。
PS:这种机制是使 .NET 程序集更安全的关键。您不能替换指向方法的指针。它会破坏组件的签名。
JIT 编译也严重依赖这些表
正如@GlennFerrieLive 指出的那样,对 GetType 的调用是一个InternalCall
,这意味着实现在 CLR 本身中,而不是在任何 BCL 中。
我的理解是内部CLR方法从this
指针中获取运行时类型信息,基本上相当于类型的名称。然后,它从所有已加载程序集(可能在当前应用程序域中)中存在的元数据中查找完整的类型信息,这使得反射变得相当昂贵。元数据区域基本上是程序集中存在的所有类型和成员的数据库,它构建了该数据的实例Type
或Method|Property|FieldInfo
从该数据构建实例。