Zabunu je izazvalo to, što kada se kaže prosleđivanje po vrednosti, očekuje se da promenljiva koju smo prosledili ostane ne promenjena, pošto se funkciji šalje kopija te promenljive. Ali kada se referenti tip šalje funkciji, i u funkciji ga izmenimo, te promene će ostati.
Stvar je u tome što se u ovom slučaju ne pravi kopija samog objekta, nego se pravi kopija reference koja pokazuje na taj objekat. Znači mi ustvari funkciji šaljemo kopiju reference.
Dakle Java podržava prosleđivanje samo po vrednosti, dok C# podržava prosleđivanje i po referenci. Po defaultu C# prosleđuje promenljive po vrednosti (isto kao i Java), a da bi prosleđivao po referenci dodaje se još ref.
Na kraju najbolje da se sve ovo pokaže jednim primerom.
Code:
class Program
{
static void Main(string[] args)
{
Koordinata mojaKoordinata = new Koordinata(0, 0); //objedat koji cemo menjati po vrednosti
Koordinata mojaKoordinataRef = new Koordinata(0, 0); //objedat koji cemo menjati po referenci
int mojBroj = 0; //broj koji cemo menjati po vrednosti
int mojBrojRef = 0; //broj koji cemo menjati po referenci
Console.WriteLine("Pre izmene:");
PrikazTeksta(mojaKoordinata, mojaKoordinataRef, mojBroj, mojBrojRef); //prikazuje vrednosti za sve promenljive
Menjaj(mojaKoordinata, ref mojaKoordinataRef, mojBroj, ref mojBrojRef);
Console.WriteLine("Posle izmene:");
PrikazTeksta(mojaKoordinata, mojaKoordinataRef, mojBroj, mojBrojRef);
IzmenaObjekta(mojaKoordinata, ref mojaKoordinataRef); //postavlja objekte na null
Console.WriteLine("Izmena koordinata:");
Console.WriteLine("Da li je koordinata null: po vrednosti je " + (mojaKoordinata == null).ToString() + " po referenci je " + (mojaKoordinataRef == null).ToString());
Console.Read(); //da nam se ne zatvori ekran :)
}
static void PrikazTeksta(Koordinata koord, Koordinata koordRef, int a, int b)
{
Console.WriteLine("Koordinata je " + koord.vrednostX.ToString() + "," + koord.vrednostY.ToString() + " po referenci je " + koordRef.vrednostX.ToString() + "," + koordRef.vrednostY.ToString());
Console.WriteLine("Broj je " + a.ToString() + " po referenci je " + b.ToString());
}
static void Menjaj(Koordinata koord, ref Koordinata koordRef, int a, ref int b)
{
koord.vrednostX = 5;
koord.vrednostY = 5;
koordRef.vrednostX = 5;
koordRef.vrednostY = 5;
a = 5;
b = 5;
Console.WriteLine("Za vreme izmene:");
PrikazTeksta(koord, koordRef, a, b);
}
static void IzmenaObjekta(Koordinata koord, ref Koordinata koordRef)
{
koord = null;
koordRef = null;
}
}
class Koordinata
{
int x, y;
public Koordinata(int x, int y)
{
this.x = x;
this.y = y;
}
public int vrednostX
{
get { return x; }
set { x = value; }
}
public int vrednostY
{
get { return y; }
set { y = value; }
}
}
class Program
{
static void Main(string[] args)
{
Koordinata mojaKoordinata = new Koordinata(0, 0); //objedat koji cemo menjati po vrednosti
Koordinata mojaKoordinataRef = new Koordinata(0, 0); //objedat koji cemo menjati po referenci
int mojBroj = 0; //broj koji cemo menjati po vrednosti
int mojBrojRef = 0; //broj koji cemo menjati po referenci
Console.WriteLine("Pre izmene:");
PrikazTeksta(mojaKoordinata, mojaKoordinataRef, mojBroj, mojBrojRef); //prikazuje vrednosti za sve promenljive
Menjaj(mojaKoordinata, ref mojaKoordinataRef, mojBroj, ref mojBrojRef);
Console.WriteLine("Posle izmene:");
PrikazTeksta(mojaKoordinata, mojaKoordinataRef, mojBroj, mojBrojRef);
IzmenaObjekta(mojaKoordinata, ref mojaKoordinataRef); //postavlja objekte na null
Console.WriteLine("Izmena koordinata:");
Console.WriteLine("Da li je koordinata null: po vrednosti je " + (mojaKoordinata == null).ToString() + " po referenci je " + (mojaKoordinataRef == null).ToString());
Console.Read(); //da nam se ne zatvori ekran :)
}
static void PrikazTeksta(Koordinata koord, Koordinata koordRef, int a, int b)
{
Console.WriteLine("Koordinata je " + koord.vrednostX.ToString() + "," + koord.vrednostY.ToString() + " po referenci je " + koordRef.vrednostX.ToString() + "," + koordRef.vrednostY.ToString());
Console.WriteLine("Broj je " + a.ToString() + " po referenci je " + b.ToString());
}
static void Menjaj(Koordinata koord, ref Koordinata koordRef, int a, ref int b)
{
koord.vrednostX = 5;
koord.vrednostY = 5;
koordRef.vrednostX = 5;
koordRef.vrednostY = 5;
a = 5;
b = 5;
Console.WriteLine("Za vreme izmene:");
PrikazTeksta(koord, koordRef, a, b);
}
static void IzmenaObjekta(Koordinata koord, ref Koordinata koordRef)
{
koord = null;
koordRef = null;
}
}
class Koordinata
{
int x, y;
public Koordinata(int x, int y)
{
this.x = x;
this.y = y;
}
public int vrednostX
{
get { return x; }
set { x = value; }
}
public int vrednostY
{
get { return y; }
set { y = value; }
}
}
Dobijamo sledeći rezultat:
Code:
Pre izmene:
Koordinata je 0,0 po referenci je 0,0
Broj je 0 po referenci je 0
Za vreme izmene:
Koordinata je 5,5 po referenci je 5,5
Broj je 5 po referenci je 5
Pre izmene:
Koordinata je 0,0 po referenci je 0,0
Broj je 0 po referenci je 0
Za vreme izmene:
Koordinata je 5,5 po referenci je 5,5
Broj je 5 po referenci je 5
Zasad je sve bilo jasno, ali da vidimo sledeći rezultat
Code:
Posle izmene:
Koordinata je 5,5 po referenci je 5,5
Broj je 0 po referenci je 5
Posle izmene:
Koordinata je 5,5 po referenci je 5,5
Broj je 0 po referenci je 5
Prvi red, zar ne bi trebalo da je prva vrednost ostala 0,0?
Ne, jer kao što sam na početku rekao mi prosleđujemo kopiju reference, koja i dalje pokazuje na isti objekat.
Mi smo u funkciji Menjaj izmenili objekat, pa ove dve različite reference pokazuju na taj izmenjen objekat.
Code:
Izmena koordinata:
Da li je koordinata null: po vrednosti je False po referenci je True
Izmena koordinata:
Da li je koordinata null: po vrednosti je False po referenci je True
Na kraju smo u funkciji IzmenaObjekta, prosledili jedan parametar po vrednosti, a drugi po referenci, i oba postavili da budu null.
U prvom slučaju pravimo kopiju reference, tu kopiju postavljamo na null, pa po izlasku iz funkcije, original je ostao ne promenjen, tj. nije null.
U drugom slučaju se ne pravi kopija pa će referenca ostati izmenjena.