.Net dünyasında temel olarak iki tip parametre vardır. Değer (value) veya referans (referance) geçmek. Parametre olarak değer geçmek, stack’de duran işaretçinin içerisindeki değeri ya da adresi (referans türlü ise) vermek demektir. Referans geçmek ise, işaretçinin ram üzerindeki adresini (işaretçi de ram üzerinde yer kaplar ve bir adresi vardır) vermek anlamına gelir. Örnekler üzerinden ilerleyerek, yaptığımız atamaları sembolize etmeye çalışalım.
Test_int adlı metot yazalım. Parametre olarak bir integer deger alsın ve içeride o integer’ın değerini değiştirsin.
class Program
{
static void Main(string[] args)
{
int sayi = 40;
Test_int(sayi);
Console.WriteLine(sayi);
}
static void Test_int(int a)
{
a = 200;
}
}
Programı çalıştırdığımızda sayı adlı değişkenin değerinin 40 olduğunu görürüz. Sebebi basittir. Local değişkenler, tanımlandıkları metot işini bitirdiğinde ram’den düşerler. Durumu sembolize etmeye çalışalım.
Main metodu içerisindeki sayı adlı değişkenin ram’deki sembolik şekli yukarıdaki gibidir. Test_int metodu çalıştığında ram’e “a” adında locak bir değişken çıkar ve parametre olarak sayi adlı değişkenin değeri gönderilir. (ref veya out anahtar sözcüklerini kullanmadan parametre geçmek, değer geçmek anlamına gelmektedir.)
NOT: F23 ve F71 benim verdiğim sembolik bir değerdir. Değişkenin ram üzerindeki adresini temsil etmektedir.
Test_int metodunun içerisine girildiğinde a adl local değişkenin değeri 200 olur.
Daha sonra Test_int metodu işini bitirir ve içerisindeki local değişkenler ram’den düşer.
Main metodu kaldığı satırdan çalışmaya devam eder. Bir sonraki adım, “sayi” adlı değişkenin ekrana yazdırılma işlemidir. 40 değerine sahip olduğu için de ekranda 40’ı görmüş olduk.
Şimdi de aynı örneği ref anahtar sözcüğünü kullanarak yapmaya çalışalım. Test_int_ref adında bir metot yazalım. Tek fark, parametrenin ref anahtar sözcüğü ile birlikte verilmesi olacaktır. Yani “sayi” adlı değişkenin değerini değil de, referansını (ram’deki adresini) göndermiş olacağız.
class Program
{
static void Main(string[] args)
{
int sayi = 40;
Test_int_ref(ref sayi);
Console.WriteLine(sayi);
}
static void Test_int_ref(ref int a)
{
a = 200;
}
}
Metot bizden integer tipinden bir değer değil de, integer tipinden bir işaretçinin ram’deki adresini beklemektedir. Yani Main metodu içerisinde “sayi” adlı değişkenin direkt olarak kendisini parametre olarak verdiğimizi düşünebiliriz. Test_int_ref adlı metot içerisindeki “a” adlı local değişken, direkt olarak “sayi” değişkenin temsil etmektedir. Şimdi durumu sembolize etmeye çalışalım.
Main metodu çalışmaya başladığında ram’e “sayi” adlı local bir değişken çıkar ve değeri 40’dır.
ikinci satıra geçildğinde Test_int_ref adlı metoda çağrı yapılır ve parametre olarak sayı değişkenin referansı verilir.
“a” adlı locak değişken, “sayi” adlı değişkeni temsil eder, yani “sayi” değişkenin ram üzerindeki adresini tutar. Dolayısı ile a değişkeni üzerinde yapacağımız herhangi bir işlem direkt olarak “sayi” adlı değişkenin üzerinde de gerçekleşecektir. Metot içerisinde “a” adlı değişkenin değerine 200 atanır.
Test_int_ref metodu işini bitirdiğinde “a” değişkeni ram’den düşer.
Main metodu çalışmaya kaldığı yerden devam eder. Artık “sayi” değişkeni 200 değerine sahiptir. Dolayısı ile ekran çıktısı aşağıdaki gibi olacaktır.
Değer türlü tipler için durum yukarıdaki gibidir. Şimdi de referans türlü tip için bir test yapalım. Urun adında id,ad ve fiyat alanlarına sahip bir sınıf yazalım. Test_urun adında geriye void dönen bir metodumuz olsun. Parametre olarak bir Urun alsın ve aldığı bu Urun’un fiyatını değiştirsin.
class Urun
{
public int Id { get; set; }
public string Ad { get; set; }
public double Fiyat { get; set; }
public Urun(int id, string ad, double fiyat)
{
Id = id;
Ad = ad;
Fiyat = fiyat;
}
}
class Program
{
static void Main(string[] args)
{
Urun urun = new Urun(1, "Monitör", 200);
Test_urun(urun);
Console.WriteLine(urun.Fiyat);
}
static void Test_urun(Urun u)
{
u.Fiyat = 999;
}
}
Main metodu çalışmaya başladığında ram’e bir Urun nesne örneği çıkar. Ram’de tutulma şeklide sembolik olarak aşağıdaki gibidir.
NOT: K30, M60, B15 sembolik olarak ram’deki adresleri belirtmektedir.
ikinci satıra geçildiğinde Test_urun metot çağırılır ve parametre olarak “urun” adlı değişkenin değeri gönderilir. Bu değişkenin değeri, içerisinde tuttuğu adres bilgisidir.
Metot içerisinde, parametre olarak gelen Urun’un fiyatına 999 değeri atanır.
Test_urun metodu işini bitirdiğinde “u” adlı locak değişken ram’den düşer.
Main metodu çalışmaya kaldığı yerden devam eder. “urun” adlı değişkenin işaret ettiği nesnenin fiyat alanında 999 değeri olduğundan ötürü, program çalıştığında ekranda bu değeri görürüz.
Bu şekilde bakıldığında referans türlü tiplerde “ref” anahtar sözcüğünün kullanılıp kullanılmamasının sonucu değiştirmeyeceği kanısına varılabilir. Ancak durum gözüktüğü gibi değildir. Urun sınıfı üzerinden başka bir örnek ile devam edelim.
class Urun
{
public int Id { get; set; }
public string Ad { get; set; }
public double Fiyat { get; set; }
public Urun(int id, string ad, double fiyat)
{
Id = id;
Ad = ad;
Fiyat = fiyat;
}
}
class Program
{
static void Main(string[] args)
{
Urun urun = new Urun(1, "Monitör", 200);
Console.WriteLine(urun.Fiyat);
Test_urun2(urun);
Console.WriteLine(urun.Fiyat);
}
static void Test_urun2(Urun u)
{
u = new Urun(2, "laptop", 1500);
u.Fiyat = 2750;
}
}
Main metodu çalıştığında ram’e bir Urun nesnesi çıkar. Urunun fiyatı ekrana yazdırılır.
urun adlı değişken heap’de adı monitör olan bir nesneyi işaret etmektedir. Test_urun2 adlı metot çağrıldığında “u” adlı local bir değişken ram’e çıkar. Değeri, parametre olarak gelen “urun” değişkenin değeridir. Yani adı monitör olan nesneyi işaret etmektedir.
Metot içerisinde yeni bir nesne üretilir ve adresi “u” değişkenine verilir.
Daha sonra u adlı değişkenin işaret ettiği nesnenin fiyatına 2750 değeri atanır.
Metot işini bitirdiğinde u adlı değişken ram’den düşer.
ram’de üzerinde Y99 adresine sahip nesne, stack’de herhangi bir işaretçi tarafından işaret edilmedinden dolayı ram’den düşer. Dolayısı ile P50 adresindeki nesne de aynı sebepten ötürü ram’den düşer.
Main metodu çalışmaya kaldığı yerden devam eder. Metot çağrısı yapıldıktan sonra urun adlı değişkenin işaret ettiği nesnenin fiyatı ekrana tekrar yazdırılır.
Gördüğümüz gibi, sonuç ilk yaptığımız örnekten farklıdır. urun adlı değişken aynı nesneyi işaret etmektedir. Şimdi de ref anahtar sözcüğü kullanarak aynı örnek üzerinden inceleme yapmaya devam edelim.
class Urun
{
public int Id { get; set; }
public string Ad { get; set; }
public double Fiyat { get; set; }
public Urun(int id, string ad, double fiyat)
{
Id = id;
Ad = ad;
Fiyat = fiyat;
}
}
class Program
{
static void Main(string[] args)
{
Urun urun = new Urun(1, "Monitör", 200);
Console.WriteLine(urun.Fiyat);
Test_urun2_ref(ref urun);
Console.WriteLine(urun.Fiyat);
}
static void Test_urun2_ref(ref Urun u)
{
u = new Urun(2, "laptop", 1500);
u.Fiyat = 2750;
}
}
Main metodu çalışmaya başlar ve ram’e “urun” adında bir değişken çıkar. Daha sonra bu değişkenin işaret ettiği Urun nesnesinin fiyatı ekrana yazdırılır.
Daha sonra Test_urun2_ref adlı metot çağrılır ve parametre olarak “urun” değişkenin referansı verilir.
Metot içerisine girildiğinde heap’e yeni bir Urun nesne örneği çıkar ve adresi “u” işaretçisine atanır.
“u” nun işaret ettiği nesnenin fiyatına 2750 değeri atanır. Daha sonra metot sonlanır. “u” değişkeni ile, M60 ve B15 adreslerindeki nesneler sahipsiz kaldığından dolayı ram’den düşerler.
Main metodu çalışmaya kaldığı yerden devam eder ve ekrana “urun” değişkeninin işaret ettiği nesnenin fiyatı yazdırılır. Artık işaret edilen nesne adı “laptop” olan üründür. Main metodunun girişinde oluşan nesne ram’den düşmüştür.
Gördüğümüz gibi, referans türlü tiplerde ref anahtar sözcüğünün kullanımı farklı sonuçlar doğurabilmektedir.
Faydalı olması dileği ile…
3 yorum:
çok teşekkürler bu güzel, sade paylaşımlar için.
Gön:İsmail KAYA
Ben teşekkür ederim, faydalı olmasına sevindim.
İyi çalışmalar.
anlatımınız gercekten cok guzel olmus.
iyi calısmalar dılerım
Yorum Gönder