如何在C#中实现反射?

Dus*_*gen 20 .net c#

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

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

Gle*_*rie 16

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

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

\ sscli20\CLR\SRC\BCL\SYSTEM \反射

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

更新:对不起,但我认为这是一个死胡同. Type.GetType()调用来自System.Object的基本实现.如果你检查那个codefile(.\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();
Run Code Online (Sandbox Code Playgroud)

更新(再次):我深入挖掘并在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()
Run Code Online (Sandbox Code Playgroud)

现在,我们需要去找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
Run Code Online (Sandbox Code Playgroud)

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

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

  • 伙计,C++ 代码看起来令人难以理解,但我想我明白了要点。它取消引用指向对象的指针并获取其类型句柄。然后,它在方法表中查找类型信息(取决于 IsUnsharedMT,它返回对象方法表是否位于默认域或共享域(共享域中存储的大型对象,例如数组、指针、函数指针或 byref) 。然后它获取该类型的 objectref 并取消引用它以返回。但是,我不知道 IsThunking 或 CONTRACTL 是关于什么的。 (2认同)

Mar*_*ell 7

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


evh*_*n14 5

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

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

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

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

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

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

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

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