copia e blocco

Durante il marshalling il gestore di marshalling di interoperabilità può copiare o aggiungere i dati interessati. Tramite l'operazione di copia, una copia dei dati viene spostata da una posizione della memoria a un'altra. La figura seguente illustra le differenze esistenti tra la copia di un tipo valore e quella di un tipo passato per riferimento dalla memoria gestita a quella non gestita.

Diagram that shows how value and reference types are copied.

Il marshalling degli argomenti del metodo passati per valore a codice non gestito viene eseguito come marshalling di valori sullo stack. Il processo di copia è diretto. Gli argomenti passati per riferimento vengono passati come puntatori allo stack. Anche i tipi riferimento vengono passati per valore e per riferimento. Come illustrato nella figura seguente, i tipi riferimento passati per valore vengono copiati o bloccati:

Diagram showing reference types passed by value and by reference.

Con il blocco, i dati vengono temporaneamente bloccati nella posizione di memoria corrente, impedendone quindi il riposizionamento da parte del Garbage Collector di Common Language Runtime. I dati vengono aggiunti dal gestore di marshalling per ridurre il sovraccarico dell'operazione di copia e migliorare le prestazioni. In base al tipo, si stabilisce se i dati verranno copiati o aggiunti nel corso del processo di marshalling. Per oggetti come String, l'aggiunta viene eseguita automaticamente durante il marshalling. È tuttavia possibile aggiungere la memoria manualmente tramite la classe GCHandle.

Classi copiabili da BLT formattate

Le classi copiabili da BLT formattate hanno un layout fisso (formattato) e una rappresentazione dei dati comune sia nella memoria gestita che in quella non gestita. Quando questi tipi richiedono il marshalling, un puntatore all'oggetto nell'heap viene passato direttamente al chiamato. il quale può modificare il contenuto della posizione di memoria a cui il puntatore fa riferimento.

Nota

Il chiamato può modificare il contenuto della memoria se il parametro è contrassegnato con Out o In/Out. Al contrario, deve evitare di modificare il contenuto quando il parametro è contrassegnato con In per il marshalling, vale a dire con l'impostazione predefinita per i tipi copiabili da BLT formattati. La modifica di un oggetto In genera problemi quando la stessa classe viene esportata in una libreria dei tipi e usata per effettuare chiamate su più apartment.

Classi non copiabili da BLT formattate

Le classi non copiabili da BLT formattate hanno un layout fisso (formattato) ma la rappresentazione dei dati è diversa nella memoria gestita e in quella non gestita. Può essere necessaria la trasformazione dei dati nelle condizioni seguenti:

  • Se si esegue il marshalling di una classe non copiabile da BLT per valore, il chiamato riceve un puntatore a una copia della struttura dei dati.

  • Se si esegue il marshalling di una classe non copiabile da BLT per riferimento, il chiamato riceve un puntatore a un puntatore a una copia della struttura dei dati.

  • Se si imposta l'attributo InAttribute, la copia viene sempre inizializzata con lo stato dell'istanza. Il marshalling viene eseguito secondo necessità.

  • Se si imposta l'attributo OutAttribute, lo stato viene sempre restituito come copia all'istanza. Il marshalling viene eseguito secondo necessità.

  • Se si impostano sia InAttribute che OutAttribute, sono richieste entrambe le copie. Se si omette uno degli attributi, il gestore di marshalling può ottimizzare il processo eliminando una delle copie.

Tipi di riferimento

È possibile passare i tipi riferimento per valore o per riferimento. Quando sono passati per valore, sullo stack viene passato un puntatore al tipo. Quando sono passati per riferimento, sullo stack viene passato un puntatore a un puntatore al tipo.

Il comportamento dei tipi riferimento varia a seconda delle condizioni seguenti:

  • Se un tipo riferimento viene passato per valore e possiede membri di tipo non copiabile da BLT, i tipi vengono convertiti due volte:

    • Quando si passa un argomento al lato non gestito.

    • Al ritorno dalla chiamata.

    Per evitare inutili operazioni di copia e conversione, viene eseguito il marshalling di questi tipi come parametri in. Perché le modifiche apportate dal chiamato risultino visibili al chiamante, è necessario applicare gli attributi InAttribute e OutAttribute a un argomento in modo esplicito.

  • Se un tipo riferimento viene passato per valore e possiede solo membri di tipi copiabili da BLT, è possibile aggiungerlo durante il marshalling e le modifiche apportate ai membri del tipo dal chiamato saranno visibili al chiamante. Per ottenere questo comportamento, applicare InAttribute e OutAttribute in modo esplicito. Senza questi attributi direzionali, il gestore di marshalling di interoperabilità non esporta informazioni direzionali nella libreria dei tipi, ma come parametro in per impostazione predefinita. Potrebbero quindi verificarsi problemi con il marshalling su più apartment COM.

  • Se si passa un tipo riferimento per riferimento, il marshalling viene eseguito come In/Out per impostazione predefinita.

System.String e System.Text.StringBuilder

Quando si esegue il marshalling dei dati nel codice non gestito per valore o per riferimento, in genere i dati vengono copiati dal gestore di marshalling in un buffer secondario, eventualmente convertendo i set di caratteri nel corso della copia, e un riferimento al buffer viene passato al chiamato. A meno che non si tratti di un BSTR allocato con SysAllocString, il riferimento viene sempre allocato con CoTaskMemAlloc.

Per ottimizzare il processo nel caso in cui il marshalling di String o StringBuilder venga eseguito per valore, come nel caso di una stringa di caratteri Unicode, il gestore di marshalling passa al chiamato un puntatore diretto alle stringhe gestite nel buffer Unicode interno anziché copiarlo in uno nuovo.

Attenzione

Quando una stringa viene passata per valore, il riferimento passato dal gestore di marshalling non deve mai essere modificato dal chiamato, per evitare danni all'heap gestito.

Quando un oggetto System.String viene passato per riferimento, il contenuto della stringa viene copiato dal gestore di marshalling in un buffer secondario prima di effettuare la chiamata. Il contenuto del buffer viene quindi copiato in una nuova stringa dopo la chiamata. Grazie a questa tecnica, si garantisce che la stringa gestita immutabile rimanga inalterata.

Quando un oggetto System.Text.StringBuilder viene passato per valore, il gestore di marshalling passa un riferimento a una copia temporanea del buffer interno di StringBuilder al chiamante. Il chiamante e il chiamato devono concordare sulla dimensione del buffer. Il chiamante è responsabile della creazione di uno StringBuilder di lunghezza adeguata. Il chiamato deve prendere le precauzioni necessarie per garantire che il buffer non risulti sovraccarico. StringBuilder è un'eccezione alla regola in base alla quale i tipi riferimento passati per valore vengono passati come parametri In per impostazione predefinita, StringBuilder viene sempre passato come In/Out.

Vedi anche