Lo scopo di tale attributo è duplice:
- gestione delle chiamate in loco , se applicare l'inizializzazione variabile o non
- marshalling
Se si dovesse chiamare quel metodo da C#, o una lingua simile con la semantica simili, tale parametro sarebbe noto a il compilatore non ha bisogno di un valore iniziale.
In altre parole, si può fare questo:
int a;
CallSomeMethodWithOutParameter(out a);
e il compilatore sa che non v'è alcuna necessità di assicurare che a
ha già un valore prima di effettuare la chiamata.
D'altra parte, senza l'attributo, sarebbe necessaria la seguente, di nuovo in C#:
int a = 0; // <-- notice initialization here
CallSomeMethodWithOutParameter(ref a); // <-- and ref here
L'altro scopo è per chiamate di metodo che saranno dispiegate in un contesto di chiamata diverso, ad esempio tramite P/Invoke, verso un dominio app diverso, o verso un servizio web, per notificare le routine di marshalling che il parametro in questione conterrà un valore quando il metodo restituisce, ma non è necessario passare alcun valore nel metodo quando lo si chiama .
Questo potrebbe fare la differenza quando i parametri ei valori di ritorno devono essere impacchettati e trasportati nella posizione remota in cui passa la chiamata effettiva.
In altre parole, se si dovesse specificare che su una chiamata di metodo utilizzato per P/Invoke, no smistamento sia fatta la volontà del valore del parametro esistente quando il metodo viene chiamato, ma quando il metodo ritorna sua il valore viene ripristinato nel codice di chiamata.
Si noti che questa ottimizzazione dipende dalla routine di marshalling da utilizzare, oppure no, si tratta di dettagli di implementazione. L'attributo dice semplicemente alla routine con quale parametro può farlo, non è un'istruzione che verrà sempre seguita.
Non importa a C# solo se compilasse il codice in questione? "Ref" e "out" non sono identici al call-site?- non importa :) –In realtà, ciò significa che se la variabile non è stata scritta prima di chiamare la routine in questione, il compilatore inserirà silenziosamente il codice per inizializzare il percorso di archiviazione che contiene la variabile anziché lamentarsi (non vi è alcuna garanzia su dove verrà inserito tale codice, né vi è alcuna garanzia che una variabile che lascia e rientri nello scope non continui a utilizzare la stessa posizione di memorizzazione senza re-inizializzazione). Il compilatore non può realmente assumere che la variabile sia stata scritta, poiché non può essere sicuro che la routine chiamata effettivamente la scriva. – supercat
@supercat: dipende dal livello al quale stiamo considerando le cose. Il "controllo che il tuo codice sorgente è valido" livello * fa * presuppone che la variabile sia stata scritta. Il livello "emitting IL" non lo è, anche se una diversa implementazione rivolta a una piattaforma diversa * potrebbe * essere in grado di. –