C#nedir?com
 
YAZAR HAKKINDA
Sefer Algan
Sefer Algan
http://www.seferalgan.com
İletişme geçmek için tıklayın.
71 Makalesi yayınlanmakta.
Yazar hakkında detaylı bilgi için tıklayın.
Yayınlanan diğer makaleleri için tıklayın.
İlgili etiketler:  C# / VC#/.NET Sefer Algan
 
YAZI HAKKINDA
Türü : Makale
Serbest Köşede C#nedir?com üyelerinin hazırladıkları yazılar yayınlanır. Bu yazılar editör incelemesine girmeden yayınlanır.
Seviyesi : Başlangıç
Kategori : C# / VC#/.NET
Yayınlanma Tarihi : 26.10.2003
Okunma Sayısı : 65538
Yorum Sayısı : 4     yorum yaz
Site İçi AramaSİTE İÇİ ARAMA
Üye Girişini AçÜye GİRİŞİ
Üye girişi için tıklayın.
Kullanıcı Adı
Şifre
 
Beni her zaman hatırla
Bir hafta boyunca kullanıcı bilgilerinizi kullanıcı çıkışı yapana kadar hatırlar. (Paylaşılan bilgisayarlarda önerilmez.)
 
Şifremi / Kullanıcı Adımı unuttum.
 
.net TV RSS Serbest KÖŞE (?)
Serbest Köşede C#nedir?com üyelerinin hazırladıkları yazılar yayınlanır. Bu yazılar editör incelemesine girmeden yayınlanır.
emre TAŞ
XML - Deniz Kılınç
emre TAŞ
yazının devamı >
emre TAŞ
Decompiling and Reverse Engineering .Net Radyo
emre TAŞ
yazının devamı >
emre TAŞ
Masaüstü mü ? İnternet Mi? .Net Radyo
emre TAŞ
yazının devamı >
emre TAŞ
.Net Kavramları - .Net Radyo
emre TAŞ
yazının devamı >
emre TAŞ
Yeni Başlayanlar için - .Net Radyo
emre TAŞ
yazının devamı >
Makale Gönder Bende Yazmak İstiyorum
.net TV RSSBlogroll
Turhal Temizer
Conda install environment.yml Package 21.4.2021
Turhal Temizer
Mac OS/X Removing CUDA 21.4.2021
Burak Selim Şenyurt
Tie Fighter Değil, Project Tye! 21.4.2021
Burak Selim Şenyurt
Stackoverflow Sevgi Anketinde Yıllardır Bir Numara Çıkan Programlama Dili Rust Kimdir? 21.4.2021
  Diğer Herşey
Sponsorlar
BT Akademi
Medya Portakal
Video Hosting Sponsoru
Csharpnedir.com bir Ineta üyesidir
Uzman Abi
Her Yönüyle C# - Sefer Algan
Ref ve Out Anahtar Sözcüklerinin Kullanımı
 
Kapat
Sayfayı Yazdır Sık Kullanılanlara Ekle Arkadaşıma Gönder MySpace Del.Ico.Us Digg Facebook Google Mixx Reddit StumbleUpon
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
  • Yazılan Yorumlar
  • Yorum Yaz
ARA
12
2016
class Program { static void Main() { int x = 10; int y = 20; Degistir(x, y); } static void Degistir(int x, int y) { int temp = x; x = y; y = temp; Console.WriteLine("X = " + x.ToString()); Console.WriteLine("Y = " + y.ToString()); Console.ReadKey(); } } O KADAR UGRAŞMANIZA GEREK YOK TERS ÇEVİRMEK İÇİN BUNU KULLANIN..
ARA
18
2009
Gibi... Ayrica bas fonksiyonunda yazi icin out olmuyor. Normalde out deger gelmeyecekse kullaniliyor ama deger istiyor ve mecburen ref kullandiriliyor yada ekrana basmadan once deger atanmasi gerekiyor.Yani 2. bolumde null olarak ref?? kabul ediyor sozde etmesi gereken out kabul etmiyor. void bas(ref string yazi) { //yazi = "2"; Console.WriteLine(yazi); yazi = "1"; } void menu(out string secim) { Console.WriteLine("Deger gir"); secim = Console.ReadLine(); Program gonder = new Program(); gonder.bas(ref secim); } static void Main(string[] args) { string deger; Program test= new Program(); test.menu(out deger); Console.WriteLine(deger); }
ARA
18
2009
Merhaba, Şu tarz bir durum için ne yapılmalıdır; 2 adet fonksiyon yazdım. Mainden 1. fonksiyona gidip bir rakam girdirdim. 2. fonksiyonda ise girileni ekrana bastım ve gelen bu değeri değiştirdim. Böyle bir durumda 1. fonksiyona dönen değer ilk verilen değilde son değiştirilen oluyor. Ve main'e son değer dönüyor. 2. fonksiyonda değeri sadece referans alip üzerindeki değişikliğin sadece 2. fonksiyonda kalmasini nasil sağlayabilirim?Bunu ref ilede denedim out ilede ancak sonuç değişmedi. Ref veya out kullanarak benim atladığım bir seçenek olabilir?
EKİ
4
2006
Şunuda eklemek istiyorum. Mesela Out olarak tanımlanmış bir argümana rutin içerisinde aşağıdaki gibi değer atayamayız. static void myOut(out int t) { t = t+5 hata oluşur } ancak t argümanı ref olarak tanımlansa idi hata oluşmazdı.
Sayfalar : 1 
Yorum yazabilmek için üye girişi yapmalısınız. Üye girişi için tıklayın.
Üye değilseniz Üyel Ol linkine tıklayarak üyeliğinizi hemen başlatabilirisniz.
 
  • Bu Konuda Son 10
  • 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