c# .net

¿Cómo se implementa la reflexión en C#?



.net (4)

Me dio curiosidad por saber dónde se implementa Type.GetType() , así que eché un vistazo al ensamblaje y noté que Type.GetType() llama a base.GetType() y como Type hereda de MemberInfo eché un vistazo y se definió como _MemberInfo.GetType() que devuelve this.GetType() . Dado que no puedo encontrar el código real que muestra cómo C # puede obtener información de tipo que me gustaría saber:

¿Cómo obtiene CLR Type y MemberInfo de los objetos en Runtime?


Como señala @GlennFerrieLive, la llamada a GetType es una llamada InternalCall que significa que la implementación está dentro del CLR en sí y no en ninguno de los BCL.

Entiendo que el método CLR interno toma la información de tipo de tiempo de ejecución de this puntero, que básicamente equivale al nombre del tipo. Luego, busca la información de tipo completa de los metadatos presentes en todos los ensamblados cargados (presumiblemente, en el dominio de aplicación actual), que es lo que hace que la reflexión sea bastante costosa. El área de metadatos es básicamente una base de datos de todos los tipos y miembros presentes en el ensamblaje y construye una instancia de Type o Method|Property|FieldInfo partir de estos datos.


La fuente ACTUAL para .NET Framework 2.0 está disponible en Internet (con fines educativos) aquí: http://www.microsoft.com/en-us/download/details.aspx?id=4917

Esta es la implementación del lenguaje C #. Puedes usar 7zip para descomprimirlo. Encontrará el espacio de nombres de reflexión aquí (relativamente):

. / sscli20 / clr / src / bcl / system / reflection

Estoy investigando la implementación específica sobre la que estás preguntando, pero este es un buen comienzo.

ACTUALIZACIÓN: Lo siento, pero creo que es un callejón sin salida. Type.GetType() llama a la implementación base que proviene de System.Object. Si inspecciona ese archivo de código ( ./sscli20/clr/src/bcl/system/object.cs ) encontrará que el método es extern (consulte el código a continuación). Una inspección adicional podría descubrir la implementación, pero no está en el BCL. Sospecho que será en código C ++ en alguna parte.

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

ACTUALIZACIÓN (OTRA VEZ): Profundicé más y encontré la respuesta en la implementación de la máquina virtual CLR. (Está en C ++).

La primera pieza del rompecabezas está aquí:

/ sscli20 / clr / src / vm / ecall.cpp

Aquí vemos el código que asigna la llamada externa a una función de C ++.

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

Ahora, tenemos que encontrar ObjectNative::GetClass ... que está aquí:

/ sscli20 / clr / src / vm / comobject.cpp

Y aquí está la implementación de 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

Una última cosa, la implementación de GetTypeHandle junto con algunas otras funciones de soporte se pueden encontrar aquí:

/ sscli20 / clr / src / vm / object.cpp



Puede que no responda a tu pregunta directamente. Sin embargo, aquí hay un pequeño resumen de cómo el código administrado sabe todo acerca de los tipos.

  1. Cada vez que compila un código, el compilador analiza / analiza los archivos de origen y recopila la información que encuentra. Por ejemplo, eche un vistazo a la clase a continuación.

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

    El compilador puede ver que esta es una clase interna con dos miembros. El miembro uno es una propiedad de tipo int con setter privado. El miembro 2 es un método protegido con el nombre Met2 y el tipo booleano que toma entrada flotante (el nombre de entrada es ''entrada''). Entonces, tiene toda esta información.

  2. Almacena esta información en el montaje. Hay un par de mesas. Por ejemplo, todas las clases (tipos) salen en una tabla, los métodos viven en otra tabla. Piense en una gran cantidad de tablas SQL, aunque definitivamente no lo son.

  3. Cuando un usuario (desarrollador) desea conocer información sobre un tipo, llama al método GetType. Este método se basa en objetos ocultos, tipo puntero de objeto. Este objeto es básicamente un puntero a una tabla de clase. Cada tabla de clase tendrá un puntero al primer método en la tabla de métodos. Cada registro de método tendrá un puntero al primer parámetro en la tabla de parámetros.

PD: este mecanismo es clave para hacer que los ensamblados .NET sean más seguros. No se pueden reemplazar los punteros a los métodos. Se romperá la firma del assebmly.

La compilación JIT se basa en gran medida en estas tablas también