C# İÇerİsİndekİ DeĞer Ve Referans TÜrlerİ

Alotoputu

Katılımcı Üye
14 Eyl 2007
438
0
C# İÇERİSİNDEKİ DEĞER VE REFERANS TÜRLERİ


Değer ve Referans Türleri

Bütün programlama dillerinde olduğu gibi, C#'ta da temel veri türlerini temsil etmek üzere birtakım anahtar kelimeler kullanılmaktadır. C# içerisindeki bu veri türlerine baktığımız zaman görmekteyiz ki, herhangi bir türün alt ve üst sınırı, C# gibi .Net tabanlı programlama dillerinin hepsinde aynıdır. Bu durum bize, yazmış olduğumuz programların, herhangi bir taşma olmaksızın, diğer .NET dilleri ile uyumlu bir şekilde çalışması avantajını getirmektedir.
.Net dillerinde tanımlanan bu veri türleri, değer veya referans tabanlı olabilmektedir. Değer tabanlı veri türleri dediğimizde aklımıza yığın (stack) üzerinde tutulan tamsayı (int), ondalık kayar noktalı sayı (float) v.b. değer türleri ile birlikte numaralandırma türleri (enumerations) ve yapılar (structure) gelmektedir. Ayrıca değer türlerinde bilmemiz gereken diğer bir nokta var ki, o da yığın (stack) üzerinde bulunan bu verilerin, tanımlandığı alan dışına çıkıldığında, otomatik olarak yığından (stack) silindiğidir.
Csharp2.0.referansvalue_firat_1.jpg

Verinin Yığın (stack) Üzerindeki Hareketi

Bununla birlikte, tanımlamış olduğumuz bir değer türünün, başka bir değer türüne eşitlenmesi durumunda, varsayılan olarak, değerler arasında birebir kopyalama işlemi gerçekleştirilir.
Csharp2.0.referansvalue_firat_2.jpg

Değer Türleri Birebir Kopyalanir.

Belirttiğimiz gibi .NET tabanlı dillerde, yapılar (structers) ve numaralandırmalar (enumerations) değer türü verilerdi. Bunlardan, yapılar, kendi yapıcı metodlarına (constructor) sahip olmakla birlikte, bir yandanda yığın (stack) üzerine yazılabilmenin avantajına sahiptir.
.Net içerisinde tüm yapılar (structures) 'System.ValueType' sınıfından türemektedir. Bu sınıfın temel amacı, 'System.Object' sınıfında tanımlanan sanal (virtual) metodların üzerine yazma (override) işlemini gerçekleştirmektir. ValueType sınıfının sanal (virtual) metodlarından bazıları şekildeki gibi olmakla birlikte, tanımlamış olduğumuz yapılar bu sınıfı genişletmektedir.
Csharp2.0.referansvalue_firat_3.jpg

ValueType Sınıfının Sanal Metodları
Şimdi 'struct' anahtar kelimesini kullanarak, 'Nokta' isimli bir yapı tanımlayalım.
Csharp2.0.referansvalue_firat_4.jpg

ValueType Sınıfının Sanal Metodları

Oluşturmuş olduğumuz Nokta isimli yapımızdan bir nesne tanımlamak istediğimizde 'new' anahtar kelimesini kullanırız. Hatırlarsak, new anahtar kelimesini genellikle, heap bellek bölgesinden yer ayırmak için kullanıyorduk. Fakat System.ValueType sınıfından türemiş olan yapılar için bu durum biraz değişiklik göstermektedir. Çünkü, oluşturduğumuz yapıları kullanarak tanımlayacağımız her bir nesne, değer türünden bir veri olması nedeniyle, yığın (stack) bellek bölgesinde tutulacaktır.


Csharp2.0.referansvalue_firat_5.jpg

Fakat, new anahtar kelimesini kullanmadığımız zaman, nesnelerin herbir elemanının başlangıç değerini vermemiz gerekmektedir. Aksi takdirde, derleme hatası ile karşılaşırız. Şimdi, değer türündeki verileri daha iyi anlayabilmek için bir örnek yapalım.
Csharp2.0.referansvalue_firat_6.jpg

Değer Türleri

Örneğimizin çıktısı şekildeki gibi olacaktır.
Csharp2.0.referansvalue_firat_7.jpg

Bu örnekte, daha önce oluşturduğumuz 'Nokta' yapısını kullanarak n1 adında bir nesne yarattık. Daha sonra, 'Nokta' türündeki n2 isimli başka bir nesneye n1 nesnesini atadık. Atama işlemi sonrasında, sizin de tahmin edeceğiniz gibi, yığın (stack) üzerinde 'Nokta' türünde birbirinden bağımsız iki ayrı nesne bulunmaktadır. Bu nesnelerin birbirinden bağımsız olması nedeniyle, n2.x değerinin değişmesi n1.x değerini etkilememektedir.
Aksine, referans türü olan sınıflar managed heap üzerinde bulunmaktadır. Burada bulunan nesnelere yapılan herhangi bir atama işlemi, nesnelerin bellek (heap) üzerinde aynı referans noktasını göstermesine neden olmaktadır. Bunu daha iyi görebilmek için, örneğimizde tanımladığımız 'Nokta' isimli yapımızı, sınıf türüne dönüştürelim ve örnek çıktımıza tekrar bakalım.
Csharp2.0.referansvalue_firat_8.jpg

Csharp2.0.referansvalue_firat_9.jpg
Sınıflar referans türünden veriler olduğundan dolayı, herhangi bir sınıftan tanımlanan nesnelerin birbirlerine atanması, ilgili nesnelerin referans noktalarının eşitlenmesi, dolayısıyla her iki nesneninde bellek üzerinde aynı noktayı göstermesine neden olmaktadır.
Referans Türlerinin Değer Türleri İçerisinde Kullanılması

Referans ve değer türleri arasındaki farkı anladığımıza göre şimdi daha karmaşık yapıları incelemeye başlayabiliriz.
Şekildeki gibi özel bir yapıcı metodu bulunan 'Sekil' adında bir sınıf oluşturalım.
Csharp2.0.niteliyiciler_firat_10.jpg

Şimdi, tanımlamış olduğumuz 'Sekil' isimli bu sınıfımızı kapsayan 'Dikdortgen' isimli bir yapı (struct) tanımlayalım ve bu yapıya da özel bir yapıcı metod oluşturalım. Ayrıca şunu hatırlamamız gerekir ki yapı türünden oluşturduğumuz verilerin, varsayılan yapıcı metodu sistem tarafından korunmakta olup, tekrar tanımlanmasına izin verilmemektedir.
Csharp2.0.referansvalue_firat_11.jpg

Örneğimizde referans türünden olan 'Sekil' sınıfımızı, 'Dikdortgen' isimli yapımız içerisinde kullandık. Bu tür kullanımlarda, tamsayı türünden olan veriler, ilgili 'Dikdortgen' yapısını kullanarak oluşturduğumuz tüm nesneler içerisinde bağımsız olarak oluşturulmaktadır. Bunu yazımızın ilk bölümlerinde açıklamıştık. Peki ya bir referans türü olan sınıfımız, her bir nesne için nasıl davranacak? Değer türlerinde olduğu gibi her bir nesne için bağımsız olarak mı oluşturulacak? Yoksa bellekte aynı noktayı mı gösterecekler? Bu soruların cevabını vermeden önce, örneğimizi inceleyelim ve örneğimizin çıktısı üzerinden neyin nasıl olduğunu daha iyi görmeye çalışalım.
Csharp2.0.referansvalue_firat_12.jpg

Örneğimizde, sizin de gördüğünüz gibi önce 'Dikdortgen' yapısını kullanarak d1 isimli bir nesne oluşturuyoruz. Daha sonra bu nesneyi, d2 isminde, yeni tanımladığımız nesneye atıyoruz. Bu atama işlemi sonrası, d1 ve d2 arasındaki bağlantıyı anlayabilmek adına d2 nesnesinin değerlerini değiştiriyoruz. Şimdi, bu bağlantıyı daha iyi anlayabilmek için örneğimizin çıktısını görelim.
Csharp2.0.referansvalue_firat_13.jpg
Örnek çıktımızda da gördüğümüz gibi, d2 nesnesinin değerlerini değiştirmemiz sonrası referans türünde olan d1 nesnesinin adı 'd2' olarak değişti. Buna karşın, d1 nesnesinin değer türündeki değeri üzerinde hiçbir değişme meydana gelmedi. Bu da göstermektedir ki, referans türleri, değer türleri içerisinde olsa dahi, herhangi bir atama işlemi sonrası, bellekte aynı noktayı gösterirler. Değer türleri ise aksine, yığın (stack) üzerinde farklı alanlarda tutulduğu için, herhangi bir atama işlemi sonrası, bir değerin değişmesi, diğerini etkilemez.
Referans Türlerini Değer Olarak Geçme

Referans türlerini, herhangi bir üye fonksiyona değer olarak aktarabiliriz. Nasıl aktardığımızı görmek için önce 'Kisi' ismindeki aktaracağımız sınıf türünü oluşturalım.
Csharp2.0.referansvalue_firat_14.jpg

Şimdi, tanımlamış olduğumuz Kisi sınıfı türünden bir nesne alan ve aldığı bu nesnenin özellikleri üzerinde değişiklik yapan 'DegerIleGecis' isimli bir metod tanımlayalım.
Csharp2.0.referansvalue_firat_15.jpg

DegerIleGecis metodumuzun yapmış olduğu işlem, metoda gelen Kisi türünden bir nesnenin, yaşını değiştirmek ve ardından Kisi sınıfının yapıcı metodunu kullanarak ilgili nesnenin adını ve tekrar yaşını değiştirmeye çalışmak. Şimdi bu metodun çalışmasını test edeceğimiz örnek programımızı yazalım.
Csharp2.0.referansvalue_firat_16.jpg

İlgili metodumuzu kullanırken, sizin de görmüş olduğunuz gibi öncelikle Kisi sınıfından k1 adında yeni bir nesne tanımlıyoruz ve ilk değer atamasını yapıyoruz. Daha sonra nesnenin bilgilerini ekrana yazdırıyoruz ve ardından nesneyi DegerIleGecis metoduna gönderiyoruz. Metod içerisindeki birtakım işlemlerden sonra, nesnemizin bilgilerini tekrar ekrana yazdırıyoruz. Tanımlamış olduğumuz nesnemiz DegerIleGecis metodu içerisinde ne gibi değişikliklere uğradığını, örnek çıktımız üzerinde daha iyi görmeye çalışalım.
Csharp2.0.referansvalue_firat_17.jpg
Bu çıktımızda gördüğümüz gibi, metodumuz içerisinde ilgili nesnenin özelliklerine '.' operatörü ile direk ulaşarak değiştirebiliyoruz. Fakat, 'new' anahtar kelimesi ile ilgili sınıfın yapıcı metodu üzerinden herhangi bir değişiklik yapmaya çalıştığımızda, başarılı olamıyoruz. Bunun nedeni, daha önce de anlattığımız gibi, referans türü değişkenler, yönetilebilen bellek (managed heap) üzerinde bulunurlar ve biz new ile ilgili sınıfın herhangi bir yapıcı metodunu kullandığımızda, bellek üzerinde yeni bir adresi göstermiş oluruz. İşte bu noktada, değer türü veri aktardığımız metodlar içerisinde, ilgili nesnenin bellekte gösterdiği adresi değiştirme şansımız olmadığından, new operatörü ile yapmaya çalıştığımız hiçbir değişiklik ilgili nesneye yansımayacaktır.
Referans Türlerini Referans Olarak Geçme

Şimdi, değer ile geçişi öğrendiğimize göre, referans türünden bir nesneyi, herhangi bir metoda referans olarak nasıl geçireceğimize bakalım. Öncelikle, geçişi göstermek için kullacağımız, 'ReferansIleGecis' metodumuzu oluşturalım. Burada, daha önceki yazılarımızda üzerinde durduğumuz, parametre niteleyicilerinden, 'ref' niteleyicisini kullanacağımızı hatırlatmak isterim.
Csharp2.0.referansvalue_firat_18.jpg

Hatırlarsanız, değer ile aktarım sırasında, ilgili nesnenin adres değerini değiştirememe gibi bir kısıtlama ile karşı karşıya kalıyorduk. Şimdi yapacağımız örneğimizde de göreceğimiz gibi referans ile geçiş sırasında ise böyle bir kısıtlama bulunmamaktadır.
Csharp2.0.referansvalue_firat_19.jpg

Burada, referans ile geçişe izin verildiği için 'new' anahtar kelimesi ile yaptığımız değişiklikler nesnemize yansıyacaktır. Örneğimizin çıktısı üzerinde bunu daha iyi görelim.
Csharp2.0.referansvalue_firat_20.jpg

Bir nesneyi referans ile geçirirken, hatırlamamız gereken, ilgili nesnenin hem özelliklerini, hem de referans ettiği adresi ilgili metod içerisinde değiştirebiliyor olmamızdır.
Sonuç

Bu yazımızda, değer ve referans türlerinin neler olduğunu gördük. Bunların herhangi bir metoda aktarımı sırasında nelere dikkat etmemiz gerektiği üzerinde durduk. Ve son olarak da değer ve referans türlerini, metodlara aktardıktan sonra, üzerlerinde ne gibi değişikler yapabileceğimizi inceledik. Önümüzdeki yazımızda boxing ve unboxing işlemlerinin ne olduğunu ve bu işlemleri uygulamalarımızda nasıl kullanacağımız üzerinde duracağız.
 
Üst

Turkhackteam.org internet sitesi 5651 sayılı kanun’un 2. maddesinin 1. fıkrasının m) bendi ile aynı kanunun 5. maddesi kapsamında "Yer Sağlayıcı" konumundadır. İçerikler ön onay olmaksızın tamamen kullanıcılar tarafından oluşturulmaktadır. Turkhackteam.org; Yer sağlayıcı olarak, kullanıcılar tarafından oluşturulan içeriği ya da hukuka aykırı paylaşımı kontrol etmekle ya da araştırmakla yükümlü değildir. Türkhackteam saldırı timleri Türk sitelerine hiçbir zararlı faaliyette bulunmaz. Türkhackteam üyelerinin yaptığı bireysel hack faaliyetlerinden Türkhackteam sorumlu değildir. Sitelerinize Türkhackteam ismi kullanılarak hack faaliyetinde bulunulursa, site-sunucu erişim loglarından bu faaliyeti gerçekleştiren ip adresini tespit edip diğer kanıtlarla birlikte savcılığa suç duyurusunda bulununuz.