La fonte ACTUAL per .NET Framework 2.0 è disponibile su Internet (per scopi didattici) qui:http://www.microsoft.com/en-us/download/details.aspx?id=4917
Questa è l'implementazione del linguaggio C#. Puoi usare 7zip per decomprimerlo. Troverai lo spazio dei nomi di riflessione qui (relativamente):
Sto cercando l'implementazione specifica di cui stai chiedendo, ma questo è un buon inizio.
AGGIORNAMENTO: Scusa, ma penso che sia un vicolo cieco. Type.GetType()
chiama l'implementazione di base che proviene da System.Object. Se controlli quel file di codice (.\sscli20\clr\src\bcl\system\object.cs
) troverai che il metodo è extern
(vedi codice sotto). Un'ulteriore ispezione potrebbe scoprire l'implementazione, ma non è nel BCL. Sospetto che sarà nel codice C++ da qualche parte.
// Returns a Type object which represent this object instance.
//
[MethodImplAttribute(MethodImplOptions.InternalCall)]
public extern Type GetType();
AGGIORNAMENTO (ANCORA): Ho scavato più a fondo e ho trovato la risposta nell'implementazione della macchina virtuale CLR stessa. (È in C++).
Il primo pezzo del puzzle è qui:
Qui vediamo il codice che associa la chiamata esterna a una funzione C++.
FCFuncStart(gObjectFuncs)
FCIntrinsic("GetType", ObjectNative::GetClass, CORINFO_INTRINSIC_Object_GetType)
FCFuncElement("InternalGetHashCode", ObjectNative::GetHashCode)
FCFuncElement("InternalEquals", ObjectNative::Equals)
FCFuncElement("MemberwiseClone", ObjectNative::Clone)
FCFuncEnd()
Ora dobbiamo cercare ObjectNative::GetClass
... che è qui:
ed ecco l'implementazione di 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
Un'ultima cosa, l'implementazione di GetTypeHandle
insieme ad alcune altre funzioni di supporto possono essere trovate qui:
Le parti più significative della riflessione sono implementate nell'ambito della CLI stessa. Pertanto, puoi guardare la sorgente di riferimento della CLI MS (aka "Rotor") o la sorgente mono. Ma:sarà principalmente C/C++. I dettagli di implementazione dell'API pubblica (MethodInfo
, Type
ecc.) può essere C#.
Potrebbe non rispondere direttamente alla tua domanda. Tuttavia, ecco un piccolo schema di come il codice gestito sa tutto sui tipi.
-
Ogni volta che si compila il codice, il compilatore analizza/analizza i file di origine e raccoglie le informazioni che incontra. Ad esempio, dai un'occhiata alla classe qui sotto.
class A { public int Prop1 {get; private set;} protected bool Met2(float input) {return true;} }
Il compilatore può vedere che questa è una classe interna con due membri. Il membro uno è una proprietà di tipo int con setter privato. Il membro 2 è un metodo protetto con nome Met2 e tipo boolean che accetta l'input float (il nome dell'input è 'input'). Quindi, ha tutte queste informazioni.
-
Memorizza queste informazioni nell'assieme. Ci sono un paio di tavoli. Ad esempio le classi (tipi) lasciano tutte in una tabella, i metodi vivono in un'altra tabella. Pensa a turno alle tabelle SQL, anche se sicuramente non lo sono.
-
Quando un utente (sviluppatore) vuole conoscere le informazioni su un tipo, chiama il metodo GetType. Questo metodo si basa sul campo nascosto degli oggetti - tipo puntatore oggetto. Questo oggetto è fondamentalmente un puntatore a una tabella di classe. Ogni tabella di classe avrà un puntatore al primo metodo nella tabella dei metodi. Ciascun record di metodo avrà un puntatore al primo parametro nella tabella dei parametri.
PS:questo meccanismo è la chiave per rendere più sicuri gli assiemi .NET. Non è possibile sostituire i puntatori ai metodi. Rompere la firma dell'assemblea.
Anche la compilazione JIT fa molto affidamento su queste tabelle