Discussione:
Passaggio per valore e per riferimento?
(troppo vecchio per rispondere)
Giorgio#
2007-01-30 14:32:27 UTC
Permalink
Salve gente,
visto che io credevo di sapere la differenza che ci stà nella chiamata ad un
metodo con passaggio di parametro per valore e per riferimento.
E visto che oggi ho scoperto che questo funzionamento in C# sembra
differente rispetto al C++ o anche al C (cioè quello che sapevo io), volevo
sollevare questo nubbio a voi super esperti:

Qual'è la differenza tra passaggio per valore e per riferimento in C#?

GRAZIE a tutti quelli che vorrano dare il loro apporto per confortare la mia
amara scoperta odierna.

P.S. state attenti a non sbagliare anche voi però.
Alex
2007-01-30 15:17:51 UTC
Permalink
Be lo dice quasi la parola stessa... per riferimento viene passato il
riferimento (indirizzo) a cui "punta" l'oggetto passato in argomento,
per valore viene passata una copia (ovvero un nuovo oggetto con scope
interno al metodo).
Cosa avresti scoperto?
Post by Giorgio#
Salve gente,
visto che io credevo di sapere la differenza che ci stà nella chiamata ad un
metodo con passaggio di parametro per valore e per riferimento.
E visto che oggi ho scoperto che questo funzionamento in C# sembra
differente rispetto al C++ o anche al C (cioè quello che sapevo io), volevo
Qual'è la differenza tra passaggio per valore e per riferimento in C#?
GRAZIE a tutti quelli che vorrano dare il loro apporto per confortare la mia
amara scoperta odierna.
P.S. state attenti a non sbagliare anche voi però.
Raffaele Rialdi [MVP]
2007-01-30 15:22:58 UTC
Permalink
Post by Giorgio#
visto che io credevo di sapere la differenza che ci stà nella
chiamata ad un metodo con passaggio di parametro per valore e per
riferimento. E visto che oggi ho scoperto che questo funzionamento in C#
sembra
differente rispetto al C++ o anche al C (cioè quello che sapevo io),
Qual'è la differenza tra passaggio per valore e per riferimento in C#?
Enormemente differente da C/C++, e uno dei concetti principali del framework
(non è peculiare di C#)

Faccio una carrellata molto *grossolana e veloce*...
I tipi come hai scoperto sono due: valuetype e reftype.
* I valuetype sono struct, enum e tipi di base. Quando li passi come
argomento vengono *duplicati* e allocati sullo stack e questo è un dato da
tenere sempre a mente. Ci sono poi altre piccole differenze che lascio a te
da guardare su msdn alla voce struct del reference di C#. I valuetype non
sono soggetti alla Garbage Collection.
* I reftype sono tutto ciò che è una class, interface e delegate e sono
sempre allocati nell'heap. In sostanza li usi sempre tramite un puntatore
che è il reference. Quando li passi come parametro non fai altro che passare
il reference. I reftype sono soggetti alla Garbage Collection.

*Le casistiche nel passaggio parametri sono 4:*
- passare un valuetype by value: il tipo viene copiato; ogni modifica locale
non influisce il valore del chiamante

- passare un valuetype by reference: viene passato un puntatore al tipo;
ogni modifica locale è fatta in realtà sull'oggetto del chiamante

- passare un referencetype by value: il reference all'oggetto viene
duplicato localmente. I due reference puntano allo stesso oggetto, quindi
ogni metodo/proprietà che agisce sull'oggetto stesso modificherà l'oggetto.
La stringa non è mutabile e quindi apparirà come fossero due oggetti
distinti anche se non è così.

- passare un referencetype by reference: passi un riferimento del reference
(come il ** del C). Puoi cambiare il reference del chiamante. Utile
raramente, per lo più nelle chiamate PInvoke.


Infine è bene ricordare che quando un valuetype può essere boxato (per
esempio quando viene messo dentro un object) e questa è una operazione molto
costosa. L'inverso è l'unboxing (cioè il valuetype viene estratto
dall'object che lo contiene).
Post by Giorgio#
GRAZIE a tutti quelli che vorrano dare il loro apporto per confortare
la mia amara scoperta odierna.
P.S. state attenti a non sbagliare anche voi però.
Perché mai amara? :) È una delle prime cose messe in evidenza nel Richter,
un libro immancabile.
E poi questa differenza è una salvezza ;)
--
Raffaele Rialdi
Microsoft .NET MVP http://mvp.support.microsoft.com -
http://italy.mvps.org UGIdotNET - User Group Italiano .NET
http://www.ugidotnet.org Weblog: http://blogs.ugidotnet.org/raffaele
Giorgio#
2007-01-30 16:20:38 UTC
Permalink
Post by Raffaele Rialdi [MVP]
Post by Giorgio#
visto che io credevo di sapere la differenza che ci stà nella
chiamata ad un metodo con passaggio di parametro per valore e per
riferimento. E visto che oggi ho scoperto che questo funzionamento
in C# sembra
differente rispetto al C++ o anche al C (cioè quello che sapevo io),
Qual'è la differenza tra passaggio per valore e per riferimento in C#?
Enormemente differente da C/C++, e uno dei concetti principali del
framework (non è peculiare di C#)
Faccio una carrellata molto *grossolana e veloce*...
I tipi come hai scoperto sono due: valuetype e reftype.
* I valuetype sono struct, enum e tipi di base. Quando li passi come
argomento vengono *duplicati* e allocati sullo stack e questo è un
dato da tenere sempre a mente. Ci sono poi altre piccole differenze
che lascio a te da guardare su msdn alla voce struct del reference di
C#. I valuetype non sono soggetti alla Garbage Collection.
* I reftype sono tutto ciò che è una class, interface e delegate e
sono sempre allocati nell'heap. In sostanza li usi sempre tramite un
puntatore che è il reference. Quando li passi come parametro non fai
altro che passare il reference. I reftype sono soggetti alla Garbage
Collection.
*Le casistiche nel passaggio parametri sono 4:*
- passare un valuetype by value: il tipo viene copiato; ogni modifica
locale non influisce il valore del chiamante
- passare un valuetype by reference: viene passato un puntatore al
tipo; ogni modifica locale è fatta in realtà sull'oggetto del
chiamante
- passare un referencetype by value: il reference all'oggetto viene
duplicato localmente. I due reference puntano allo stesso oggetto,
quindi ogni metodo/proprietà che agisce sull'oggetto stesso
modificherà l'oggetto. La stringa non è mutabile e quindi apparirà
come fossero due oggetti distinti anche se non è così.
- passare un referencetype by reference: passi un riferimento del
reference (come il ** del C). Puoi cambiare il reference del
chiamante. Utile raramente, per lo più nelle chiamate PInvoke.
Infine è bene ricordare che quando un valuetype può essere boxato (per
esempio quando viene messo dentro un object) e questa è una
operazione molto costosa. L'inverso è l'unboxing (cioè il valuetype
viene estratto dall'object che lo contiene).
Post by Giorgio#
GRAZIE a tutti quelli che vorrano dare il loro apporto per confortare
la mia amara scoperta odierna.
P.S. state attenti a non sbagliare anche voi però.
Perché mai amara? :) È una delle prime cose messe in evidenza nel
Richter, un libro immancabile.
E poi questa differenza è una salvezza ;)
Si si, è proprio come dice Raffaele; grazie, sei stato preciso, puntuale e
chiarificatore.

Preciso inoltre che la mia "scoperta" si riferisce agli ultimi due casi,
ossia <<passagio di parametri per i reference type>>, di
cui certo che ne ero a conoscenza, ma per il discorso inerente ne facevo un
tuttuno con i valuetype, pensando erroneamente che anche per i referencetype
nel passaggio byValue questi venissero copiati nello stack e non si andasse
ad agire sullo stesso oggetto ma su una copia. Mentre quello che accade è
che se ne fà nello scope locale una copia del "puntatore" passato, che
effetivamente punta allo stesso oggetto presente nell'heap. Tutto qua.
Se volete potete dare un'occhiata qua (fonte della mia scoperta), cè anche
un bell'esempio sull'argomento:

http://www.c-sharpcorner.com/UploadFile/sachin.nigam/Diffbwreftypeandvalue11152005072944AM/Diffbwreftypeandvalue.aspx

la mia amarezza era solo ironica, sono contento di imparare (con umiltà)
ogni giorno una cosa nuova, senza aver paura di fare brutte figure quando
espongo i miei dubbi.

GRAZIE.
Raffaele Rialdi [MVP]
2007-01-30 20:28:40 UTC
Permalink
Post by Giorgio#
la mia amarezza era solo ironica, sono contento di imparare (con
umiltà) ogni giorno una cosa nuova, senza aver paura di fare brutte
figure quando espongo i miei dubbi.
GRAZIE.
Nessun problema, prego :)
--
Raffaele Rialdi
Microsoft .NET MVP http://mvp.support.microsoft.com -
http://italy.mvps.org UGIdotNET - User Group Italiano .NET
http://www.ugidotnet.org Weblog: http://blogs.ugidotnet.org/raffaele
Chri
2007-01-31 18:40:05 UTC
Permalink
Ma se ho una una funzione del tipo:
void MyFunc(Object obj)
{
...
}
e voglio passargli una struttura es: MyStruct(), come faccio a passargli il
referrence di MyStruct?

--> MyFunc(&Mystruct) ?
Post by Raffaele Rialdi [MVP]
Post by Giorgio#
visto che io credevo di sapere la differenza che ci stà nella
chiamata ad un metodo con passaggio di parametro per valore e per
riferimento. E visto che oggi ho scoperto che questo funzionamento in C#
sembra
differente rispetto al C++ o anche al C (cioè quello che sapevo io),
Qual'è la differenza tra passaggio per valore e per riferimento in C#?
Enormemente differente da C/C++, e uno dei concetti principali del
framework (non è peculiare di C#)
Faccio una carrellata molto *grossolana e veloce*...
I tipi come hai scoperto sono due: valuetype e reftype.
* I valuetype sono struct, enum e tipi di base. Quando li passi come
argomento vengono *duplicati* e allocati sullo stack e questo è un dato
da tenere sempre a mente. Ci sono poi altre piccole differenze che lascio
a te da guardare su msdn alla voce struct del reference di C#. I valuetype
non sono soggetti alla Garbage Collection.
* I reftype sono tutto ciò che è una class, interface e delegate e sono
sempre allocati nell'heap. In sostanza li usi sempre tramite un puntatore
che è il reference. Quando li passi come parametro non fai altro che
passare il reference. I reftype sono soggetti alla Garbage Collection.
*Le casistiche nel passaggio parametri sono 4:*
- passare un valuetype by value: il tipo viene copiato; ogni modifica
locale non influisce il valore del chiamante
- passare un valuetype by reference: viene passato un puntatore al tipo;
ogni modifica locale è fatta in realtà sull'oggetto del chiamante
- passare un referencetype by value: il reference all'oggetto viene
duplicato localmente. I due reference puntano allo stesso oggetto, quindi
ogni metodo/proprietà che agisce sull'oggetto stesso modificherà
l'oggetto. La stringa non è mutabile e quindi apparirà come fossero due
oggetti distinti anche se non è così.
- passare un referencetype by reference: passi un riferimento del
reference (come il ** del C). Puoi cambiare il reference del chiamante.
Utile raramente, per lo più nelle chiamate PInvoke.
Infine è bene ricordare che quando un valuetype può essere boxato (per
esempio quando viene messo dentro un object) e questa è una operazione
molto costosa. L'inverso è l'unboxing (cioè il valuetype viene estratto
dall'object che lo contiene).
Post by Giorgio#
GRAZIE a tutti quelli che vorrano dare il loro apporto per confortare
la mia amara scoperta odierna.
P.S. state attenti a non sbagliare anche voi però.
Perché mai amara? :) È una delle prime cose messe in evidenza nel Richter,
un libro immancabile.
E poi questa differenza è una salvezza ;)
--
Raffaele Rialdi
Microsoft .NET MVP http://mvp.support.microsoft.com -
http://italy.mvps.org UGIdotNET - User Group Italiano .NET
http://www.ugidotnet.org Weblog: http://blogs.ugidotnet.org/raffaele
Raffaele Rialdi [MVP]
2007-01-31 21:14:53 UTC
Permalink
Post by Chri
void MyFunc(Object obj)
{
...
}
e voglio passargli una struttura es: MyStruct(), come faccio a
passargli il referrence di MyStruct?
--> MyFunc(&Mystruct) ?
Innanzitutto la cosa che deve attirare la tua attenzione subito è che stai
passando un valuetype (struct) a una funzione che prende un object ...
quindi avverrà un boxing che è da evitare il più possibile.

Per quanto riguarda il reference, non è come c++ che usi &, ma devi usare la
keyword "ref"
MyFunc(ref Mystruct)

Altri esempi qui:
http://msdn2.microsoft.com/en-us/library/14akc2c7(VS.80).aspx
--
Raffaele Rialdi
Microsoft .NET MVP http://mvp.support.microsoft.com -
http://italy.mvps.org UGIdotNET - User Group Italiano .NET
http://www.ugidotnet.org Weblog: http://blogs.ugidotnet.org/raffaele
Giulio Petrucci
2007-02-05 11:44:13 UTC
Permalink
Ciao Raffaele,
Post by Raffaele Rialdi [MVP]
Faccio una carrellata molto *grossolana e veloce*...
...ma più che sufficiente! ;-)
In realtà torno sull'argomento in particolare per una delle quattro
Post by Raffaele Rialdi [MVP]
- passare un valuetype by reference: viene passato un puntatore al tipo;
ogni modifica locale è fatta in realtà sull'oggetto del chiamante
supponiamo che io abbia due variabli

bool pippo = true;
int pluto = 16;

ed una classe VariablePlaceholder che altro non fa che wrapparsi attorno
ad un object, come faccio a passargli queste due variabili? Credo di
dover implementare un costruttore che accetti un object come argomento:

internal class VariablePlaceholder
{
protected object _o;
internal VariablePlaceholder(object v)
{
_o = v;
}
}

ora, se io voglio che i cambiamenti fatti su pippo e pluto si riflettano
automaticamente sui membri _o dei relativi placeholders, come posso fare?

Ciao e grazie,
Giulio

--
OnAir: Motorhead - I Am The Sword
Raffaele Rialdi [MVP]
2007-02-07 09:03:01 UTC
Permalink
Post by Giulio Petrucci
...ma più che sufficiente! ;-)
:)
Post by Giulio Petrucci
supponiamo che io abbia due variabli
bool pippo = true;
int pluto = 16;
ed una classe VariablePlaceholder che altro non fa che wrapparsi
attorno ad un object, come faccio a passargli queste due variabili?
Credo di dover implementare un costruttore che accetti un object come
internal class VariablePlaceholder
{
protected object _o;
internal VariablePlaceholder(object v)
{
_o = v;
}
}
ora, se io voglio che i cambiamenti fatti su pippo e pluto si
riflettano automaticamente sui membri _o dei relativi placeholders,
come posso fare?
L'operazione che hai scritto tu, implica il boxing che crea di fatto un
reference type che ospita il valuetype. Le operazioni di boxing vanno
evitate quanto più è possibile perché abbattono le performance.
Non avendo usato "ref" nel passaggio parametri il tuo esempio non si
configura nella categoria di "passare un valuetype by reference" ma
semplicemente il passaggio di valuetype by value con una operazione di
boxing.

il passaggio per riferimento è molto più semplice ed è meglio non farlo
passando da object
internal VariablePlaceholder(ref int myvar) {...}
In questo caso, quando fai dei cambiamenti su myvar, questi verranno
riflessi sulla variabile che è stata passata a quel costruttore.
--
Raffaele Rialdi
Microsoft .NET MVP http://mvp.support.microsoft.com -
http://italy.mvps.org UGIdotNET - User Group Italiano .NET
http://www.ugidotnet.org Weblog: http://blogs.ugidotnet.org/raffaele
Loading...