How is Reflection implemented in C#?

前端 未结 4 721
我寻月下人不归
我寻月下人不归 2020-12-09 09:54

I got curious as to where Type.GetType() is implemented, so I took a peek at the assembly and noticed Type.GetType() calls base.GetType()

相关标签:
4条回答
  • 2020-12-09 10:14

    The most significant parts of reflection are implemented as part of the CLI itself. As such, you could look at either the MS CLI reference source (aka "Rotor"), or the mono source. But: it will mostly be C/C++. The public API implementation details (MethodInfo, Type etc) may be C#.

    0 讨论(0)
  • 2020-12-09 10:15

    As @GlennFerrieLive points out, the call to GetType is an InternalCall which means the implementation is within the CLR itself and not in any of the BCL.

    My understanding is that the internal CLR method takes the runtime type information from the this pointer, which basically amounts to the name of the type. It then look up the complete type information from the metadata present in all loaded assemblies (presumably, in the current appdomain), which is what makes reflection rather expensive. The metadata area is basically a database of all the types and members present in the assembly and it constructs an instance of Type or Method|Property|FieldInfo from this data.

    0 讨论(0)
  • 2020-12-09 10:29

    The ACTUAL source for .NET Framework 2.0 is available on the internet (for educational purposes) here: http://www.microsoft.com/en-us/download/details.aspx?id=4917

    This is the C# Language implementation. You can use 7zip to unpack it. You will find the reflection namespace here (relatively):

    .\sscli20\clr\src\bcl\system\reflection

    I am digging for the specific implementation you are asking about, but this is a good start.

    UPDATE: Sorry, but I think its a dead end. Type.GetType() calls to the base implementation which comes from System.Object. If you inspect that codefile (.\sscli20\clr\src\bcl\system\object.cs) you will find the method is extern (see code below). Further inspect could uncover the implementation, but its not in the BCL. I suspect it will be in C++ code somewhere.

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

    UPDATE (AGAIN): I dug deeper and found the answer in the implementation of the CLR virtual machine itself. (Its in C++).

    The first piece of puzzle is here:

    \sscli20\clr\src\vm\ecall.cpp

    Here we see the code that maps the external call to an C++ function.

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

    Now, we need to go find ObjectNative::GetClass ... which is here:

    \sscli20\clr\src\vm\comobject.cpp

    and here is the implementation of 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
    

    One last thing, the implementation of GetTypeHandle along with some other supporting functions can be found in here:

    \sscli20\clr\src\vm\object.cpp

    0 讨论(0)
  • 2020-12-09 10:31

    It might not answer you question directly. However, here is a little outline of how managed code knows everything about types.

    1. Whenever you compile code the compiler analyzes/parses the source files and collects information it encounters. For example take a look at class below.

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

      The compiler can see that this is an internal class with two members. Member one is a property of type int with private setter. Member 2 is a protected method with name Met2 and type boolean that takes float input (input name is 'input'). So, it has all this information.

    2. It stores this information in the assembly. There are a couple of tables. For example classes (types) all leave in one table, methods live in another table. Think in turms of SQL tables, though they are definitely are not.

    3. When a user (developer) wants to know information about a type it calls GetType method. This method relies on objects hidden field - type object pointer. This object is basically a pointer to a class table. Each class table will have a pointer to the first method in methods table. Each method record will have a pointer to the first parameter in the parameters table.

    PS: this mechamism is key to making .NET assemblies more secure. You cannot replace pointers to methods. It will break the signature of the assebmly.

    JIT compilation relies heavily on this tables as well

    0 讨论(0)
提交回复
热议问题