Lo standard CLR non richiede uno stack o un heap, quindi prima lasciamolo fuori. Ma C # implementato su carta non è molto utile. Descrivo qui le implementazioni che possiamo eseguire con "in pratica" il codice, come Microsoft C # o Mono C #. Indipendentemente da ciò, il metodo e le variabili locali hanno una relazione concettuale con le classi e le istanze dell'oggetto che devi capire, perché non è specifico di C #, è lo stesso per i linguaggi del computer in generale.
I metodi di istanza sono memorizzati nello stesso modo in cui sono usati i metodi statici.
I metodi fanno parte di code
(in CLR, bytecode), sono istruzioni compilate, codici opzionali CLR di basso livello che costituiscono l'assembly. Quindi nel modello C # non fanno parte di un heap, l'heap è per data
. ( Vedi nota a fondo nota ). Nelle lingue che non sono orientate agli oggetti, ci sono semplici funzioni. In quelle lingue, le funzioni sono solo codice che riceve argomenti. In CLR una funzione semplice è un metodo statico (o metodo di classe). L'unica differenza in una funzione e in un metodo è che lo zucchero sintattico fa sembrare che la funzione sia di proprietà, ma il suo oggetto è in realtà solo il primo argomento "implicito" (this), e nella maggior parte dei linguaggi viene prima della chiamata al metodo, es. %codice%. Il primo argomento della funzione deve ancora essere caricato da un'istruzione; in CLIL MSIL, obj.Foo()
viene caricato da this
tranne nel caso di un metodo statico. Quindi ldarg.0
equivale a obj.Foo(arg)
.
Quando compilate una classe, il compilatore emette un set di istruzioni che rappresentano il metodo e lo impacchetta in un segmento di codice.
La relazione del metodo con l'oggetto è in realtà simile alla relazione tra classe e oggetto. Il metodo è parte della classe (cioè parte del tipo , non parte dell'oggetto. Il metodo è simile a dati statici , ma i "dati metodo" capita Come i campi statici, i metodi esistono prima e senza alcuna esistenza di un'istanza di oggetto e sono solo una parte del tipo di oggetto. Potrei avere 1.000.000 di istanze di una stringa, ma c'è una singola copia di Foo(obj,arg)
da qualche parte.
Per quanto riguarda le variabili locali di un metodo, non esistono finché non viene chiamato il metodo. All'inizio di un metodo CLR, il frame di chiamata assicura spazio per tutte le variabili locali in quel metodo. Sono noti in anticipo, ma sono semplicemente notazione formale fino all'esecuzione del metodo, quindi diventano indirizzi di dati reali . Un'istruzione dice al CLR quanto spazio dedicare. I valori delle variabili locali sono concettualmente e praticamente in pila, ma mappati ai registri. Le variabili sono "locali" rispetto all'ambito del metodo e si allontanano quando il metodo restituisce (sebbene gli oggetti a cui si riferiscono possano non esserlo). Ci sono istruzioni per gestirli in CLR. Analizziamo un campione approssimativo di MSIL (assembly IL per CLR) per il tuo metodo string::Concat(string)
.
.method void MyClass::Doit()
{
.locals init([0]int myint) // declares the locals for the method
ldc.i4.5
stloc 'myint' // initialize myint to 0
ret
}
I locals sono mappati in maniera aggressiva ai registri della CPU reali dal compilatore JIT in modo che esistano principalmente su uno stack quando CLR sta interpretando o verificando il bytecode. In pratica, i locals esistono nei registri, ma si riversano su una pila nell'hardware di basso livello.
Infine, per qualsiasi linguaggio del computer, ci sono 3 gruppi principali di sintassi.
- Digitare dichiarazioni e definizioni (idee formali, regole di compilazione e metadati)
- Algorithmic (codice, metodi, istruzioni, espressioni)
- Dati e variabili (dati)
Attenzione: i sistemi Runtime sono comunemente implementati in C o C ++. Un assembly CLR e i relativi metodi vengono caricati nell'heap di runtime della lingua host utilizzata per scrivere il CLR. Ma concettualmente si tratta di un heap diverso da "heap" a cui si sta accedendo all'interno del CLR.