2015-11-21 43 views
5

Sono curioso di sapere come C# si comporta quando si passa il valore/tipi di riferimento in un metodo. Mi piacerebbe passare un tipo di valore in box nel metodo "AddThree". L'idea è di entrare nella funzione chiamante (Main) il risultato delle operazioni eseguite all'interno di "AddThree".Tipo di valore di boxe per inviarlo a un metodo e ottenere il risultato

static void Main(string[] args) 
{ 
    int age = 3; 
    object myBox = age; 
    AddThree(myBox); 
    // here myBox = 3 but I was expecting to be = 6 
} 

private static void AddThree(object age2) 
{ 
    age2 = (int)age2 + 3; 
} 

Ho provato questo con i tipi di riferimento puri come stringa e ottengo lo stesso risultato. Se "avvolgo" il mio int all'interno di una classe e io uso la classe "wrap" in questo esempio funziona come mi aspetto, cioè, ottengo myBox = 6. Se modifico la firma del metodo "AddThree" per passare il parametro per ref, questo restituisce anche 6. Ma, Non voglio modificare la firma o creare una classe wrapper, voglio solo boxare il valore.

+0

Non c'è modo di farlo senza cambiare la firma poiché è necessario che 'age2' sia un parametro' ref'. – Lee

risposta

2

Non voglio modificare la firma o creare una classe wrapper, ho voglio scatola appena il valore.

Quindi questo sarà un problema. Il metodo passa un int in scatola, quindi lo disattiva e aggiunge 3 allo age2 locale, che provoca un'altra operazione di boxing, quindi getta via il valore. Di fatto, stai assoggiando age2 a due oggetti diversi nell'heap, non puntano allo stesso oggetto. Senza modificare la firma del metodo, questo non sarà possibile.

Se si guarda alla IL generato per AddThree, vedrete chiaramente:

AddThree: 
IL_0000: nop   
IL_0001: ldarg.0  
IL_0002: unbox.any System.Int32 // unbox age2 
IL_0007: ldc.i4.3 // load 3 
IL_0008: add   // add the two together 
IL_0009: box   System.Int32 // box the result 
IL_000E: starg.s  00 
IL_0010: ret  

È Unbox il valore, aggiungere 3 e poi casella nuovamente il valore, ma non avete mai restituite.

per visualizzare questo caso ulteriormente, provare restituendo il valore appena confezionato dal metodo (solo per il gusto della prova), e utilizzare object.ReferenceEquals confrontare entrambi:

static void Main(string[] args) 
{ 
    int age = 3; 
    object myBox = age; 
    var otherBox = AddThree(myBox); 
    Console.WriteLine(object.ReferenceEquals(otherBox, myBox)); // False 
} 

private static object AddThree(object age2) 
{ 
    age2 = (int)age2 + 3; 
    return age2; 
} 
1

Assegnazione di un nuovo valore di un il parametro metodo non passato da ref non cambierà il riferimento originale.

Nel tuo caso, age2 (il parametro metodo) è una copia di myBox. Entrambi fanno riferimento allo stesso oggetto (il numero di serie), ma l'assegnazione a age2 non cambia myBox. Fa semplicemente riferimento a un altro oggetto con age2.

In realtà, non ha nulla a che fare con la boxe. È solo il modo in cui i parametri vengono passati ai metodi.

+0

Riguarda il pugilato, se param fosse int, il ref sarebbe di aiuto qui. Ma la boxe crea una copia temporanea dell'originale int, e la modifica di questa copia verrà comunque persa, con e senza riferimento. – ISanych

+0

@ISanych L'OP voleva 'myBox' (il boxed) per cambiare, non' age' (il 'int'):' // here myBox = 3 ma mi aspettavo di essere = 6'. Passare il parametro come 'ref object' lo farebbe. –

+0

hai ragione, ho perso parte che OP voleva valore in scatola. – ISanych