Evet, konumuz veri tipleri. Gerçi internette herhangi bir yazılım dili için veri tipleri ile ilgili binlerce yazı bulabilirsiniz zaten. "3-4 tane ingilizce terim, ne var bunda sende canım!" diyerek geçiştirebilir ve direk kodlamaya geçebilirsiniz. Zamanında ben de dahil, çoğu yazılımcının bu hataya düştüğünü gördüğüm için başka bir yaklaşım getirmek istediğimden böyle kısa bir yazı yazıyorum. Aslında daha çocuk yaşta bile cebirdeki denklem ve eşitsizliklere giriş ile beraber başımıza musallat olan X'e karşılık gelir diyebiliriz. Hani bağımlısı, bağımsızı olan; fizikte, kimyada kağıda dökülen denklemin bilinmeyeni olan, hayranı olduğum büyük üstat Ömer Hayyam'ın bize hediyesi olan X. Bilgisayarlarda ilk kullanıldığı zamanlarda kavram olarak da benzer bir kavram iken, günümüzde belleklerin bölgelere ayrılması ile veriye daha hızlı erişim ve belleğinin etkin kullanımı amacı ile kullanımı daha da geliştirilmiştir. Ama ben teknik anlamından ziyade olası en basit şekliyle kafanızda canlandırmaya çalışacağım. Yoksa teknik olarak çok daha ayrıntılı bir konudur ve özellikle, işler karmaşıklaşmaya başlayıp örneğin işletim sistemi yazmak gibi kaynak kullanımının hayati önem taşıdığı benzer projelerde eğer gereken önemi göstermezsiniz, üzerine çıkacağınız katlar ilerde temelin çökmesine neden olacaktır! Yani bu makale kod yazmada acele edenler için değildir, evde denemeyiniz! smiley

Şimdi işletim sisteminizin hesap makinesini açın. Çeşitli işlemler yapıp bir sonuç elde ediyor ve elde ettiğiniz bu değeri, başka işlemlerde kullanmak için hafızaya almak istiyorsunuz diyelim. Bu sayıyı makinenin hafızasına kaydetmek için M+ tuşuna basarsınız. En kaba tabiriyle değişken; işte hafızaya almak için bastığımız bu tuşun işlevini görür. Ama tabi programlama dillerinde hesap makinesindeki gibi tek değişkenlik bir sınır olması söz konusu olamaz. Bizler için bunun bir sınırı yoktur. 'Yoktur'dan kastım günümüzdeki ram kapasiteleri ile değişkenlerin ramde kapladıkları boyutlar göz önüne alınırsa "neredeyse yoktur". Bizim M+ tuşumuzdan birçok sayıda bulunur. Ayrıca hesap makinesinde tek bir değeri tuttuğumuz için buna isim vermeye gerek olmasa da biz değişkeni hafızaya çıkartırken bir isim verir ve o değişkene ulaşmamız gerektiğinde bu isim üzerinden ulaşırız.

Yine mesela yemeğimizi yedik, üzerine şöyle demli bir çay alacağız diyelim. Çayı içebilmek için doldurduğumuz bardak bir nevi değişkene benzetilebilir. Ortada, bir şekilde ihtiyacımız kadar olan çayı demlikten alabilme problemi var. Bu problemi ortadan kaldırmak için bardağa koyup istediğimiz yere taşıma çözümünü getirmiş oluyoruz. Çayı içtikten sonra yıkayıp bardağı kaldırırsınız, yani böyle farz ediyorum. smiley İşte değişkenler de bu şekilde ihtiyaç duyulan veri kadar tanımlanır, ister tanımlandığında ister daha sonra içi doldurulur, işi bittikten sonra C#'ın çöp toplayıcı (garbage collector) sistemi sayesinde yok edilirler. C# sizin yerinize bulaşıklarınızı toplayıp ortalığı siler süpürür. wink

Aslında şu an çok kaba tabirlerle kafanızda canlandırmaya çalışıyorum, yalnız introduction bölümünü bitirip nesne yönelime başlayan birisi bu benzetmemde kafa karışıklığı yaşayabilir. Eğer değişken konusuna henüz başladıysanız bu paragrafın devamını atlayın, yok nesne yönelime yeni başladı iseniz paragrafa devam edebilirsiniz. İşin aslı; bardağın kendisi gerçek hayatta da kendine has rengi, boyutları vb. özellikleri olan bir nesnedir. Örneğin beyaz renk, 5 cm.çapında, 10 cm. yüksekliğinde bir bardak diyelim. Bu tanımlarda kullandığımız "beyaz renk, 5cm. çap, 10 cm. yükseklik" birer değişkene karşılık gelir. Bardağı bu şekilde ayrıştırırsanız temeline inmiş olursunuz. C#'da "Temel Veri Tipleri" denmesinin sebebi de budur. Yani matematikte rakamlar olmadan hiçbir işlem yapamayacağınız gibi, C#'da da temel veri tipleri olmadan bir iş yapamazsınız. Hatta bu örneğim üzerinden gidersek, işler arka planda daha da ayrıntılı ya da daha doğru bir ifade ile değişken tanımlama mekanizması çok daha özgür bir kullanım sağlar. Şöyle bir evde yaşadığınızı düşünün: tüm hammaddeleri ve bu hammaddeleri ihtiyacınız olduğunda işleyerek size gereken eşyayı istediğiniz fonksiyonellikte ortaya çıkaran makinelerin, hatta o eşya ile işiniz bittiğinde yine aynı hammaddeye çeviren bir geri dönüşüm sisteminin olduğu bir ev. Yukarıdaki bardağa ihtiyacınız var diyelim. Değişkenler ile bardağın özelliklerini tanımlayarak bardağınız önünüze gelir, üstelik isterseniz içinde içeçeği de hazır bir şekilde. Ayrıca bu özellikler .NET içinde eğer sınıf kapsamında kullanılırsa field, eğer kontrollü bir şekilde değer girilmesi isteniyorsa aynen ingilizce karşılığında olduğu gibi properties diye geçer. Bu bardak mutfağın dışında başka bir yerde kullanılmasın gibi bir isteğimiz olursa da erişim belirleyici dediğimiz anahtar kelimeler devreye girer. Bu bardak ailede büyükler kullanabilsin ama çocuklar kullanamasın derseniz kalıtım ile bunu sağlayabilirsiniz. Ama aynı bardağı büyükler farklı, küçükler farklı hareket ya da özelliklerde kullansın isterseniz polymorphism, su içen kişi içme esnasında farklı hareketler de yapmaya zorunlu olsun derseniz interface, içerken tek bir sözünüzle sizin istediğiniz sırada hareketleri yapsın gibi tuhaf bir isteğiniz olursa delegate tipini kullanırsınız. Sizin istediğiniz hareketler dışında, içen kişi kendi hareketlerini belirlemek isterse "kullanıma açık" tanımladığınız delegate tiplerinden uygun olanını kullanarak bir event oluşturur ya da kendi oluşturduğu delegate tipi üzerinden event oluşturup bunu yapabilir. Bir tık öteye gideyim derseniz, mesela yukarıda bahsettiğim kalıtım örneğini generic sınıflar ile çok daha esnek ve özgür bir mimari sağlayabilirsiniz. Yalnız değişkenin ne olduğunu öğrenmek isteyenler, yukarıdaki uyarıma rağmen eğer bu paragrafa devam ettilerse çoktan pişman olmuşlardır bile. smiley Çünkü bu bahsettiklerim nesne yönelimli programlama ile ilgilidir. Bu konu böyle bir paragrafta bahsedilebilecek kadar basit değil tabi ama ben ana hatlarıyla girmek zorunda kaldığım için bunları yazdım. Bunlar benim rastgele bulduğum örnekler, bu küçük örneklerden sonra şimdi konuya biraz daha teknik açıdan yaklaşalım.

Her şeyden önce "Neden farklı veri tipleri ile çalışmaya ihtiyaç duyarız?" sorusuna bakalım. Farklı veri tiplerinin ramde kaplayacakları alan ve onlara yaptıracağımız işlemler farklıdır. Örneğin tamsayılar, metinsel ifadeler, mantıksal ifadeler ilk akla gelenlerdir. Mesela tamsayılarla dört işlem yaptırabiliyorken, metinsel ifadeler ile bu mümkün değildir. O nedenle hemen her programlama dilinde olduğu gibi C#'da da farklı işlemler için farklı veri tipleri bulunur. Bu şekilde hem ramde ayrılacak yerden israf etmemiş, hem de sadece o veri tipi ile yapılabilecek işlemlerin yapılmasına izin vermiş oluruz. Ayrıca bir yerlerde avantajları olarak rastlayabileceğiniz üzere, C# tip güvenli ya da tip denetimli bir dildir. Nedir bu tip güvenliği? Bu güvenlik, tip uyumu için tüm işlemlerin derleyici tarafından tip kontrolündeng eçirileceği anlamına gelir. Kural dışı olan işlemler derlenmez ve derleme zamanında hata verirler. Böylece hataları önlemeye yardımcı olarak kodunuzun güvenilirliği artırılmış olur. Bu yüzden 'tipi olmayan bir değişken' gibi bir kavram C# için söz konusu değildir. Bir değişken bildirimi yapılırken o değişkenin veri tipi kesinlikle bildirilmek zorundadır. Sonrasında da o değişkene atanan veriler, belirtilen veri tipinin sınırları ve tipi dışına çıkamaz. Bunun bir istisnası, bir değişkenin tuttuğu verinin başka bir tipe dönüştürülmesi(casting) işlemidir. Buna daha sonra değineceğiz.

C# 4.0 ile tip denetiminin derleme anında değil, çalışma zamanında yapılmasını sağlayan dynamic adlı yeni bir veri tipi getirilmiştir. Derleme anında gerçekleştirilen normal tip denetimi için bir istisnadır.
Yine derleme anında değişkenin tipini C#'ın kendi bularak atamasını yapan "var" anahtar kelimesi ile anonymous tipler de kullanılır ama bu kullanım daha çok veritabanı,XML gibi yapılardan veri çekerken gelecek veri tipinin belirlenmesinin güç olduğu durumlarda ya da bir metoda yardımcı olması için yazılması gereken class yada structlarda kullanılmalıdır. Yani uygulamadaki tüm değişkenleri "var" ile hafızaya çıkartmak gibi basit bir amatörlüğe düşerek, sonradan kodu okuyacak arakdaşların kulaklarınızı çınlatmasına izin verilmemelidir.

Değişken nedir?

Değişken teknik anlamda ise ramde belirli tipten bir veriyi tutması için ayrılan adrestir. Program içinde üretilen değerleri ramde geçici olarak saklamak amacı ile kullanılırlar. Her değişkene, ramde o değişkenin tutacağı veri tipine karşılık gelecek kadar bir yer ayrılır. Bu yere "değişkenin adresi" denir. Adresi olduğu gibi her değişkenin bir adı da vardır. Bu ad kullanılarak, değişkene değer atanabilir, atanan bu değer tekrar okunabilir ve atanan değer değiştirilebilir. Bir değişkene erişebilmek demek bu 3 isteği yerine getirebilme yeteneklerine sahip olmaktır. Bazen yazdığımız kodların işlevselliği ve güvenliği açısından farklı yerlerden ulaşılamamasını belirleyen çeşitli anahtar kelimeler kullanırız. Fakat bunlardan bahsetmek için henüz erken.

Değer Tipleri ve Referans Tipleri

C#'da veri tipleri, değer tipi ve referans tipi olmak üzere iki genel kategoride toplanır. Bu iki tip arasındaki fark, bir değişkenin ne içerdiği ile ilgilidir. Değer tipinde bir değişken 10 ya da 10,05 gibi gerçek bir değer içerirken; referans tipi bir değişken, o değere yapılan referansı içerir. Öncelikle değer tipini ele alalım.

C#'ın temelinde 13 adet veri tipi yer alır. Bu değer tiplerine primitif basit tip(primitive type) de denir. Her zaman tek bir değer içerdikleri için basit olarak nitelendirilmişlerdir. Başka bir deyişle, iki ya da daha farklı değerin biraraya gelmesinden oluşmazlar. C# tip sisteminin temelini oluşturur ve bir programın kullandığı en temel veri tiplerini sağlarlar.

Basit tiplere ek olarak Enumaration(numaralandırma) ve strucrute(yapı) olmak üzere iki ayrı veri tipi daha tanımlıdır.

Bu temel tipler aşağıdaki tablolarda görülüyor. Bu değerleri ezberlemeye kalkmayın, zira en amatör yazılımcının dahi, değer aralıklarını biliyorum diye övünecek kadar kendini komik duruma düşüreceğini sanmıyorum. Yoksa sanıyor olabilir miyim? (!) Muhtemelen olmaz diyorsunuzdur ama duyduğum için söylüyorum, olurda iş görüşmesi vb. bir yerlerde bu değerleri size soran olursa koşarak uzaklaşın. Zaten ben de MSDN'den kopyalayıp üzerinde küçük düzenlemeler yaptım. Sadece isimlerini ve genel hatlarıyla hangisini nerede kullanmanız gerektiğini bilseniz yeterli. Gördüğünüz gibi bazıları tamsayılar, bazıları kayan noktalı sayılar, karakterler, mantıksal ifadeler... Bunun gibi ayrıntılara sonraki yazılarımda devam etmeyi planlıyorum. Şimdilik benden bu kadar.

Değer Tipleri
Adı .Net Framework
(CTS) Karşılığı
Açıklama Aralık
sbyte System.Byte 8 bit işaretli tam sayı [-128, 127]
short System.Int16 16 bit işaretli tam sayı [-32.768, 32.767]
int System.Int32 32 bit işaretli tam sayı [-2.147.483.648, 2.147.483.647]
long System.Int64 64 bit işaretli tam sayı [-9.223.372.036.854.775.808, 9.223.372.036.854.775.807]
byte System.Byte 8 bit işaretsiz tam sayı [0, 255]
ushort System.UInt16 16 bit işaretsiz tam sayı [0, 65.535]
uint System.UInt32 32 bit işaretsiz tam sayı [0, 4.294.967.295]
ulong System.UInt64 64 bit işaretsiz tam sayı [0, 18.446.744.073.709.551.615]
float System.Single 32 bit tek kayan sayı
(7 basamak)
± 1,5*10-45, ± 3.4*1038~
double Sytem.Double 64 bit çift kayan sayı (15-16 basamak) ± 5*10-324, ± 1.7*10308 ~
decimal System.Decimal 128 bit ondalıklı sayı (28-29 basamak) ± 1,5*10-28, ± 7,9*1028~
bool System.Boolean 1 bit yer tutar true ya da false
char System.Char Karakterleri temsil eder 16 bit bütün unicode karakterleri
Referans Tipleri
Adı .Net Framework
(CTS) Karşılığı
Açıklama
object System.Object Bütün veri türlerinin türediği sınıf
string System.String Unicode karakterlerinden oluşan string