2012-01-11 16 views
7

La differenza tra tipi di riferimento e tipi di valore è spesso fonte di confusione per i principianti a causa della mancata comprensione di ciò che una variabile di tipo value detiene effettivamente. Sappiamo che:Tipi di riferimento: possiamo vedere il riferimento reale?

  • tipi di valore memorizzare il valore
  • I tipi di riferimento attuale solo memorizzare la di riferimento all'oggetto

E 'possibile ispezionare ogni tipo di variabile per entrambi vedere il valore o il riferimento effettivo stesso? Il riferimento è memorizzato come una sorta di valore codificato? So che i riferimenti possono essere passati per valore, quindi lo sto assumendo.

Penso che questo aiuterebbe i nuovi arrivati ​​con la loro comprensione e sarà molto interessante da esplorare.

+1

L'unica cosa che si dovrebbe vedere è un indirizzo, un numero apparentemente casuale. Perché vorresti vederlo? – Dykam

+3

Per cementare l'idea che all'interno della variabile non è l'oggetto che impostano, ma piuttosto un indirizzo. Come potremmo accedere a questo? –

+1

http://stackoverflow.com/questions/1978232/how-can-i-display-the-actual-value-of-a-reference-in-c-sharp –

risposta

10

È possibile esaminare ogni tipo di variabile per visualizzare il valore o il riferimento effettivo stesso?

Giusto per chiarire, il valore di un variabile di tipo riferimentoè riferimento. Il riferimento è il valore.

Un riferimento è un tipo di valore, proprio come un int è un tipo di valore. A differenza di un int, un riferimento è un valore che può essere solo copiato e dereferenziato; non è possibile osservare il suo valore direttamente in C#, poiché il suo valore è un dettaglio di implementazione del garbage collector.

Il riferimento è memorizzato come una sorta di valore codificato?

Sì, esattamente. In pratica, un riferimento è un numero intero a 32 o 64 bit (a seconda se si è in un processo a 32 o 64 bit) che è un puntatore a una struttura nota al garbage collector come associata ai dati dell'oggetto referenziato .

Se si desidera guardare i riferimenti direttamente, lo strumento per farlo è il debugger. Carica il codice C# nel debugger, compila, eseguilo, fai un punto di interruzione e dai uno sguardo allo stato dello stack e dei registri. Con un po 'di intelligenza dovresti essere in grado di capire quali posizioni e registri di stack corrispondono a quali variabili locali. Le posizioni corrispondenti alle variabili locali di tipo valore conterranno i valori; quelli del tipo di riferimento conterranno valori che sembrano puntatori. Se si esaminano quei puntatori nella finestra della memoria, si guarderanno le strutture gestite dal garbage collector che descrivono il contenuto dell'oggetto.

+3

Penso che sia importante notare che mentre le implementazioni .net esistenti possono memorizzare indirizzi (di record di informazioni sugli oggetti) nelle variabili di riferimento, non c'è alcuna garanzia che le future versioni lo faranno. Sarebbe possibile, ad esempio, che alcuni bit di una variabile di riferimento sarebbero un indice che seleziona uno di un numero di heap, mentre altri bit erano un indice all'interno di quell'heap. Mentre un tale sistema potrebbe essere inefficiente con i processori esistenti, la progettazione di futuri processori attorno a tale modello potrebbe consentire un utilizzo più efficiente della cache. Il codice .net esistente non dovrebbe interessare tali dettagli. – supercat

+0

@supercat: assolutamente. In realtà, i riferimenti potrebbero essere implementati come handle completamente opachi che sono significativi solo nella misura in cui sono indicizzati in una tabella di proprietà del garbage collector; non c'è motivo per cui * qualsiasi * bit in un riferimento debba avere un significato particolare. Come succede, nelle implementazioni odierne ogni bit di un riferimento * è * significativo in quanto può essere interpretato come un puntatore. Ma questo è soggetto a modifiche in qualsiasi momento. –

+0

Per curiosità, mentre le CPU esistenti probabilmente non consentirebbero tali cose di essere molto efficienti, mi chiedo se sarebbe utile che le future CPU avessero un heap di piccoli oggetti per gli oggetti i cui dati sono 8 (forse 16) byte o meno , dove ogni slot nella tabella oggetti contiene i dati dell'oggetto reali invece di un puntatore ad esso. Sulle CPU esistenti, occorrerebbero istruzioni aggiuntive per ciascun accesso dell'heap per determinare a quale heap appartenesse un dato riferimento, ma se ci fosse un'istruzione "get object address" che utilizzava un bit nel riferimento per selezionare la direzione indiretta singola o doppia ... – supercat

1

È possibile eseguire questa operazione con un oggetto bloccato abbastanza facilmente;

GCHandle gch=GCHandle.Alloc(data, GCHandleType.Pinned); 
IntPtr AddressInMemory=gch.AddrOfPinnedObject(); 
+0

Questo non funzionerà con [tipi non blittable] (http://msdn.microsoft.com/en-us/library/75dwhxf7.aspx), come quasi tutte le classi. – svick

+0

Sono stato corretto. Sembra che l'unica volta che ho avuto bisogno di questo era con i primitivi. –

1

È possibile farlo con unsafe codice:

unsafe 
    static void Main(string[] args) 
    { 
     string s = "Hello"; 

     fixed (char* pc = s) 
     {     
      IntPtr p = (IntPtr)pc; 
      Console.WriteLine(p); // here is your meaningless address 
     }    
    } 
+0

Questo crea una copia fissata di s, quindi perché non si scrive direttamente? –

+0

Non useremo 's' per niente. –

+0

@EugenRieck Hai una fonte per questa affermazione? Non vedo nessuna copia qui. – CodesInChaos

5

Questo è probabilmente uno per Jon Skeet, ma potrebbe avere una diversa angolazione su di esso:

Non ti preoccupare troppo circa come queste cose sono rappresentate in memoria. A meno che tu non abbia letto tutte le specifiche del linguaggio - chi lo fa comunque? - Non hai davvero bisogno di sapere. Veramente. Non preoccupatevi di memorizzare quali dati sono archiviati, dove è probabile che si tratti di un'implementazione specifica.

Invece, pensa in termini di semantica, ad es. che un tipo di valore passato a una funzione è copiato, mentre un tipo di riferimento è referenziato. Roba del genere.

In realtà non si vuole sapere cosa contiene effettivamente una dichiarazione di un tipo. Credimi. Quello che vuoi sapere, è come si comporta.

+2

+1 Ecco dove Eric Lippert [dice] (http://blogs.msdn.com/b/ericlippert/archive/2009/02/17/references-are-not-addresses.aspx) la stessa cosa.Gli indirizzi sono dettagli di implementazione, le specifiche del linguaggio non menzionano gli indirizzi quando si specificano i riferimenti. Scopri come si comportano e non come funzionano. – MarkJ

+2

Mentre sono d'accordo con la tua affermazione, non credo che sia proprio al punto della domanda. Penso che gli piacerebbe sapere come farlo - non le tue opinioni sul perché non è importante. Appoggiandoti a come funziona la funzionalità complessa puoi renderti un ingegnere migliore anche se non trovi un uso immediato per quella conoscenza. –

+0

Mentre io ringrazio entrambi e sono d'accordo con la tua risposta, non affronta il punto della mia domanda. Mi piacerebbe solo accedere all'indirizzo ** solo per dimostrare che è lì ** nessun altro motivo. Sono d'accordo con @ AdamG.Carstensen. –

Problemi correlati