|
Ref ve Out Anahtar Sözcüklerinin Kullanımı |
|
Gönderiliyor lütfen bekleyin... |
|
|
Bu yazıda C#'ın önemli
iki anahtar kelimesi olan ve değer türleride dahil olmak üzere bütün veri türlerini
referans yolu ile metotlara aktarmamızı sağlayan ref ve out'un kullanımını
göstereceğim.
C# dilinde temel olarak iki veri türü vardır. Bunlardan birincisi referans türleri
ikincisi ise değer türleridir. Referans türleri bir ifade(metot çağrımı, atama
ifadesi vs.) içinde kullanıldığı zaman nesnenin bellekteki adresi üzerinden işlem
yapılır. Yani nesnenin bütün verisi ayrıca kopyalanmaz. Değer türlerinde ise durum
daha farklıdır. Değer türleri yani int, byte,bool gibi veri türleri herhangi bir
ifade içinde kullanılırsa değişkenin yeni bir kopyası çıkarılır ve işlemler bu
yeni kopya üzerinden gerçekleştirilir. Dolayısıyla orjinal nesnenin değeri hiç
bir şekilde değiştirilemez. Asıl konumuza geçmeden önce değişkenlerin referans
yolu ile aktarımının ne demek olduğunu ve bu iki tür arasındaki farkı daha iyi
anlamak için basit bir örnek vermekte fayda görüyorum.
Aşağıdaki programdaki gibi x ve y gibi iki int türünden değişkenimiz
olsun. Bu değişkenlerin değerlerini değiştirmek(swap) için Degistir() isimli bir
metot yazmak istediğimizi düşünelim. Bu metot ilk akla gelebilecek şekilde aşağıdaki
gibi yazılır.
using
System;
namespace
ConsoleApplication2
{
class Class1
{
static
void Main()
{
int
x = 10;
int
y = 20;
Degistir(x,y);
Console.WriteLine("X
= " + x.ToString());
Console.WriteLine("Y
= " + y.ToString());
}
static
void Degistir(int x, int
y)
{
int
temp = x;
x
= y;
y
= temp;
}
}
}
|
Yukarıdaki programı
derleyip çalıştırdığımızda x ve y değişkenlerinin değerlerinin değiştirilmediğini
ve aynı değerde kaldıklarını görürüz. Bunun sebebi Degistir() metoduna gelen
x ve y değişkenleri ile Main() metodunda tanımlamış olduğumuz x ve y değişkenlerinden
tamamen bağımsız yeni değişkenler olmasıdır. Dolayısıyla Degistir() metodunda
yaptığımız değişiklikler orjinal değişkenlerimizi hiç bir şekilde etkilememiştir.
Değişkenlerin bu şekilde aktarılmasına "değer yolu ile aktarma" yada
"pass by value" denilmektedir.
Yukarıdaki programı aşağıdaki gibi biraz değiştirip x ve y değişkenleri bir
sınıf aracılığıyla metota gönderirsek değiştirme işlemini yapabiliriz.
using
System;
namespace
ConsoleApplication2
{
class C
{
public
int deger;
public
C(int x)
{
deger
= x;
}
}
class Class1
{
static
void Main()
{
C
x = new C(10);
C
y = new C(20);
Degistir(x,y);
Console.WriteLine("X
= " + x.deger.ToString());
Console.WriteLine("Y
= " + y.deger.ToString());
}
static
void Degistir(C x, C y)
{
int
temp = x.deger;
x.deger
= y.deger;
y.deger
= temp;
}
}
}
|
Bu progrmı derleyip
çalıştırdığımızda x ve y nesnelerinin deger üye elamanlarının yer değiştirildiğini
göreceksiniz. Yer değiştirmeyi yapabilmemizin sebebi x ve y değişkenlerinin
referans yolu ile metoda geçirilmesidir. Yani Degistir() metodundaki x ve y
değişkenleri ile Main() metodundaki x ve y değişkenleri bellekteki aynı bölgeyi
temsil etmektedirler. Dolayısıyla Degistir() metodunda yaptığımız bir değişiklik
Main() metodundaki değişkene de yansıyacaktır. Nesnelerin metotlara bu şekilde
aktarılmasına ise "referans yolu ile aktarım" yada "pass by reference"
denilmektedir.
Bir referans tipi olan string türü ile ilgili önemli bir istisna vardır.
string referans türü olmasına rağmen metotlara string türünden değişkenler geçirilirken
değer tiplerinde olduğu gibi kopyalanarak geçirilirler. Yani int türünden bir
değişken ile string türünden bir değişken metotlara değer yolu ile aktarılırlar.
Bunu test etmek için birinci programdaki int türü yerine string türünü kullanabilirsiniz.
Ref
Anahtar Sözcüğü
Yukarıda denildiği
gibi değer tipleri(int, double, byte vs.) metotlara kopyalanarak geçirilirler
yani değişkenin birebir yeni bir kopyası oluşturulur. Ancak bazı durumlarda
değer tiplerini de referansları ile metotlara geçirmek isteyebiliriz. C ve C++
dillerinde değer tiplerini referans yolu ile geçirmek için göstericilerden faydalanır.
Yani metotlara değişkenlerin adresleri geçirilir. C# ta bu işlemi yapmak için
gösterici yerine yeni bir anahtar sözcük olan ref kullanılır. ref anahtar
sözcüğü değer türlerinin metotlara referans yolu ile geçirilmesini sağlar. Referans
türleri zaten referans yolu ile geçirildiği için bu türler için ref anahtar
sözcüğünü kullanmak gereksizdir. Ancak kullanımı tamamen geçerli kılınmıştır.
ref sözcüğü metot çağrımında ve metot bildiriminde aynı anda kullanılmalıdır.
Yani metot bildiriminde ref ile birlikte kullanılan bir değişken, metot çağrılırken
ref ile çağrılmalıdır. Yukarıda yazdığımız birinci programı ref sözcüğünün kullanımı
ile yeniden düzenlersek Degistir() metodunun istediğimiz şekilde çalışmasını
sağlayabiliriz.
using
System;
namespace
ConsoleApplication2
{
class Class1
{
static
void Main()
{
int
x = 10;
int
y = 20;
Degistir(ref
x,ref y);
Console.WriteLine("X
= " + x.ToString());
Console.WriteLine("Y
= " + y.ToString());
}
static
void Degistir(ref int
x, ref int y)
{
int
temp = x;
x
= y;
y
= temp;
}
}
}
|
Bu programı derleyip
çalıştırdığımızda x ve y değişkenlerinin değerlerinin değiştirildiğini göreceksiniz.
Çünkü Degistir() metoundaki x ve y değişkenleri ile Main() metodundaki x ve
ye değişkenleri aynı bellek bölgesindeki değeri temsil etmektedirler. Birinde
yapılan değişiklik diğerinide etkilemektedir. Yani ilk durumdan farklı olarak
ortada iki değişken yoktur, tek bir değişken vardır.
Unutmamamız gereken nokta metot çağrımının da ref anahtar sözcüğü ile birlikte
yapılması zorunluluğudur. Eğer Degistir() metodunu Degistir(ref x, ref y) yerine
Degistir(x,y) şeklinde çağırmış olsaydık derleme aşamasında
Argument '1': cannot convert from 'int' to 'ref int'
Argument '2': cannot convert from 'int' to 'ref int'
hatalarını alırdık.
ref sözcüğünün kullanımı ile ilgili diğer bir önemli nokta ise ref ile kullanılacak
değişkenlere mutlaka değer atanmış olma zorunluluğudur. Herhangi bir değer verilmemiş
değişkeni ref ile de olsa kullanamayız. Kullandığımız takdirde ise derleme aşamasında
"Use of unassigned local variable" hatasını alırız. Bu durum ref sözcüğünün
bir kısıtı olarak düşünülebilir. Ancak birazdan göreceğimiz out sözcüğü ile
bu kısıtı ortadan kaldırabileceğimizi göreceğiz.
Out
Anahtar Sözcüğü
Out anahtar sözcüğünün
kullanım amacı ref anahtar sözcüğünün kullanımı ile tamemen aynıdır. Yani out
ile de değer tipleri referans yolu ile aktarılır. Aralarındaki tek fark out
ile kullanılacak değişkenlere ilk değer verme zorunluluğunun olmamasıdır. Yani
ref sözcüğünün kullanımındaki kısıt, out ile birlikte ortadan kaldırılmıştır.
out anahtar sözcüğünü genellikle bir metottan birden fazla geri dönüş değeri
bekliyorsak kullanırız.
Yukarıdaki Degistir()
metodunu out ile kullanılabilecek şekilde değiştirdiğimizde x ve y değişkenlerine
ilk değer verme zorunluluğumuz kalkacaktır.
ref ve out sözcüklerinin C# dilinde kullanılmasının küçük bir farkı olsada IL
dilinde ref ve out aynı şekilde implemente edilmiştir. ILDASM aracı ile Degistir()
metodunun hem ref hemde out versiyonlarının bildiriminin aşağıdaki gibi olduğunu
görürüz.
.method private
hidebysig static void Degistir(int32& x, int32& y) cil managed
{
.maxstack 2
.locals init (int32 V_0)
IL_0000: ldarg.0
IL_0001: ldind.i4
IL_0002: stloc.0
IL_0003: ldarg.0
IL_0004: ldarg.1
IL_0005: ldind.i4
IL_0006: stind.i4
IL_0007: ldarg.1
IL_0008: ldloc.0
IL_0009: stind.i4
IL_000a: ret
}
|
Bu durum ref ve
out sözcüklerinin kullanımındaki farkın C# derleyicisi ile sınırlı olduğunu
göstermektedir. Yani CLR ile ilgili bir fark değildir.
Yazıyı bitirmeden önce out anahtar sözcüğünün kullanımına bir örnek vermek istiyorum.
İki sayıdan büyük olanına geri dönen bir metot yazmak istediğimizi düşünelim.
Aynı zamanda da bu iki sayıdan birincisinin mi ikincisinin mi büyük olduğunuda
bu metotla öğrenmek istiyoruz. Her metodun tek bir geri dönüş değeri olabileceğine
göre klasik yöntemlerle bunu ideal(!)
bir şekilde gerçekleştiremeyiz. Bunun için ilk değer verilmemiş yeni bir parametreyi
daha Max() isimli metoda göndereceğiz. Bu parametre metot içinde değiştirilerek
kendisini çağıran metoda iletilecektir.
using
System;
namespace
Out
{
class Class1
{
static
void Main()
{
bool
b;
int
max = Max(9,2,out b);
Console.WriteLine(b);
}
static
int Max(int x,int
y, out bool b)
{
if(x
> y)
b
= true;
else
b
= false;
return
Math.Max(x,y);
}
}
}
|
Yukarıdaki işlemi
ref anahtar sözcüğü ile de yapabilirdik ancak bir metodun içinde değeri belirlenecek
bir değişkene ilk değer vermek gereksiz ve mantıksızdır. Dolayısıyla bir metodun
birden fazla değer geri vermesini istediğimiz durumlarda out anahtar sözcüğünü
kullanmamız daha okunabilir ve daha düzenli programcılık açısından önemlidir.
Bir sonraki yazıda görüşmek üzere...
Makale:
Ref ve Out Anahtar Sözcüklerinin Kullanımı C#, Visual C# ve .NET Sefer Algan
|
|
|
-
-
Eklenen Son 10
-
Bu Konuda Geçmiş 10
Bu Konuda Yazılmış Yazılmış 10 Makale Yükleniyor
Son Eklenen 10 Makale Yükleniyor
Bu Konuda Yazılmış Geçmiş Makaleler Yükleniyor
|
|