Giriş: C# ve .NET Ekosistemi

C#, 2000'li yılların başında Anders Hejlsberg liderliğindeki bir ekip tarafından Microsoft’ta geliştirildi. Java’nın söz dizimine benzerliğiyle dikkat çekerken, C++’ın gücünü ve Visual Basic’in hızlı uygulama geliştirme yeteneklerini bir araya getirmeyi hedefledi. C#, .NET (eskiden .NET Framework, şimdi .NET Core/.NET 5/6/7/8…) platformunun bir parçasıdır. .NET, uygulamaları geliştirmek ve çalıştırmak için kapsamlı bir sınıf kütüphanesi (Base Class Library — BCL), bir çalışma zamanı ortamı (Common Language Runtime — CLR) ve dil uyumluluğu sağlayan bir altyapıdır.

C#’ın temel özellikleri şunlardır:

Nesne Yönelimli (Object-Oriented): Her şey (neredeyse) bir nesnedir veya nesne gibi davranır. Kapsülleme (encapsulation), kalıtım (inheritance) ve çok biçimlilik (polymorphism) gibi OOP prensiplerini tam olarak destekler.
Güçlü Tipli (Strongly-Typed): Bir değişkenin türü derleme zamanında (compile-time) belirlenir ve genellikle değiştirilemez. Bu, tür uyumsuzluklarından kaynaklanan hataları çalışma zamanından önce yakalamayı sağlar ve kodu daha güvenli hale getirir.
Tip Güvenli (Type-Safe): Bir türdeki değişkene, uyumsuz başka bir türdeki değerin doğrudan atanmasını engeller (açık dönüşüm gerekebilir). Bellek güvenliğini artırır.
Bileşen Odaklı (Component-Oriented): Özellikler (properties), metotlar (methods) ve olaylar (events) gibi yapılarla yeniden kullanılabilir yazılım bileşenleri oluşturmayı kolaylaştırır.
Platformlar Arası (.NET Core ve sonrası): .NET Core ile birlikte C# uygulamaları Windows, macOS ve Linux üzerinde çalıştırılabilir hale gelmiştir.
Modern Dil Özellikleri: LINQ (Language-Integrated Query), asenkron programlama (async/await), pattern matching, lambda ifadeleri gibi modern programlama paradigmalarını destekleyen zengin özelliklere sahiptir.
Otomatik Bellek Yönetimi (Garbage Collection): CLR, oluşturulan nesneler için belleği otomatik olarak yönetir ve artık kullanılmayan nesneleri temizleyerek bellek sızıntılarını önlemeye yardımcı olur.
Bu metin, bu güçlü dilin temel söz dizimi kurallarına ve verileri temsil etmek için kullanılan temel veri türlerine odaklanacaktır.

Bölüm 1: Temel C# Program Yapısı ve Söz Dizimi Kuralları

1.1. “Merhaba, Dünya!” — İlk Program

Her programlama dilini öğrenirken klasik bir başlangıç vardır. İşte basit bir C# konsol uygulaması:

// 1. using direktifi: System isim alanını kullanacağımızı belirtir.
using System;
// 2. namespace: Kodumuzu organize etmek için kullanılan bir kapsayıcı.
namespace MerhabaDunyaApp
{
// 3. class: C#'ta kodun temel yapı taşıdır. Tüm çalıştırılabilir kod bir sınıf içinde olmalıdır.
class Program
{
// 4. Main metodu: Programın giriş noktasıdır. Uygulama buradan çalışmaya başlar.
// static: Metodun bir nesne örneği oluşturmadan çağrılabileceğini belirtir.
// void: Metodun bir değer döndürmediğini belirtir.
// string[] args: Komut satırı argümanlarını almak için kullanılır (opsiyonel).
static void Main(string[] args)
{
// 5. Konsola yazı yazdırma ifadesi.
Console.WriteLine("Merhaba, Dünya!");
// 6. Konsol penceresinin hemen kapanmaması için (opsiyonel)
// Console.ReadKey();
}
} // class Program bloğunun sonu
} // namespace MerhabaDunyaApp bloğunun sonu
Açıklamalar:

using System;: .NET kütüphanesindeki System isim alanında bulunan sınıfları (örneğin Console) doğrudan kullanabilmemizi sağlar. Aksi takdirde System.Console.WriteLine yazmamız gerekirdi. using direktifleri genellikle dosyanın en başında yer alır.
namespace MerhabaDunyaApp { … }: İsim alanları (namespaces), kodumuzu mantıksal olarak gruplandırmak ve büyük projelerde isim çakışmalarını önlemek için kullanılır. Kendi sınıflarınızı, struct’larınızı vb. isim alanları içinde organize edersiniz.
class Program { … }: C#’ta tüm çalıştırılabilir kod ve veri tanımlamaları genellikle sınıfların (veya struct, interface gibi diğer türlerin) içinde bulunur. Program burada sınıfımızın adıdır (genellikle konsol uygulamaları için varsayılan isimdir).
static void Main(string[] args) { … }: Bu, her C# uygulamasının (genellikle) sahip olduğu giriş noktası (entry point) metodudur. Program çalıştırıldığında CLR bu metodu arar ve yürütmeye başlar.
static: Main metodunun, Program sınıfının bir örneğini (nesnesini) oluşturmadan doğrudan çağrılabileceği anlamına gelir.
void: Main metodunun işletim sistemine bir değer döndürmediği anlamına gelir (int döndüren versiyonları da vardır).
string[] args: Programa dışarıdan (komut satırından) argümanlar geçilmesini sağlar. Bu argümanlar bir string dizisi olarak args parametresine gelir.
Console.WriteLine(“Merhaba, Dünya!”);: System isim alanındaki Console sınıfının WriteLine metodunu çağırarak konsola belirtilen metni yazar ve bir alt satıra geçer. C#’ta ifadeler genellikle noktalı virgül (;) ile biter.
Kod Blokları ({}): İsim alanları, sınıflar, metotlar ve kontrol yapıları (if, for vb.) kendi kod bloklarını kıvırcık parantezler ({ }) içine alır.
1.2. Temel Söz Dizimi Kuralları:

Noktalı Virgül (;): Çoğu ifade (statement) noktalı virgül ile sonlandırılır. Bu, derleyiciye ifadenin nerede bittiğini söyler.
Büyük/Küçük Harf Duyarlılığı (Case Sensitivity): C# büyük/küçük harfe duyarlıdır. myVariable, MyVariable ve myvariable üç farklı tanımlayıcıdır. Anahtar kelimeler ( class, static, void vb.) genellikle küçük harfle yazılır.
Yorumlar (Comments): Kodu açıklamak için kullanılır ve derleyici tarafından yok sayılır.
Tek Satır Yorumu: // Yorum buraya
Çok Satırlı Yorum: /* Yorumlar \n buraya \n yazılır */
XML Belgelendirme Yorumları: /// … (Metotları, sınıfları vb. belgelemek için kullanılır, IDE tarafından ipuçları oluşturmak için kullanılır).
Anahtar Kelimeler (Keywords): C# dilinin özel anlamı olan ayrılmış kelimeleridir (örn. class, namespace, using, public, private, static, void, int, string, if, else, for, while, return vb.). Değişken veya metot adı olarak doğrudan kullanılamazlar (başına @ konularak kullanılabilirler: string @class = “test”; ama genellikle kaçınılır).
Tanımlayıcılar (Identifiers): Değişkenlere, metotlara, sınıflara, isim alanlarına vb. verdiğimiz isimlerdir.
Harf, alt çizgi (_) veya @ ile başlayabilirler (genellikle harfle başlanır).
Sonraki karakterler harf, rakam veya alt çizgi olabilir.
Boşluk veya özel karakterler (+, -, * vb.) içeremezler.
Anahtar kelimelerle aynı olamazlar.
Adlandırma Kuralları (Yaygın):
Sınıf, Metot, İsim Alanı, Özellik adları: PascalCase (örn. MusteriHesabi, VeriKaydet, System.IO).
Yerel değişkenler, Metot parametreleri: camelCase (örn. kullaniciAdi, gecerliMi, alinanDeger).
Sabitler (const): Genellikle ALL_CAPS_SNAKE_CASE (örn. MAX_KULLANICI_SAYISI) veya PascalCase kullanılır.
Özel (private) alanlar: Genellikle _camelCase (örn. _aktifKullanici).
Boşluklar (Whitespace): Sekmeler, boşluklar ve yeni satırlar genellikle derleyici tarafından yok sayılır (string literalleri hariç). Kodun okunabilirliğini artırmak için girintileme (indentation) ve boş satırlar kullanılır.
Bölüm 2: Değişkenler, Sabitler ve Veri Tiplerine Giriş

2.1. Değişkenler (Variables)

Değişkenler, program çalışırken değeri değişebilen verileri saklamak için kullanılan isimlendirilmiş bellek alanlarıdır. C#’ta bir değişken kullanılmadan önce bildirilmelidir (declared). Bildirim, değişkenin türünü ve adını belirtir.

Bildirim Söz Dizimi:

dataType variableName;
dataType: Değişkenin saklayacağı verinin türü (örn. int, string, bool).
variableName: Değişkene verdiğimiz isim (tanımlayıcı kurallarına uygun).
Başlangıç Değeri Atama (Initialization):

Bir değişkene bildirim anında veya daha sonra bir değer atanabilir. Değer atama işlemi = operatörü ile yapılır.

int yas; // Bildirim
yas = 30; // Atama
string ad = "Ahmet"; // Bildirim ve atama bir arada
double piDegeri = 3.14;
bool aktifMi = true;
Önemli: C# güçlü tipli olduğu için, bir int değişkenine doğrudan bir string atayamazsınız (tür dönüşümü gerekir). C# ayrıca, bir değişkene değer atanmadan önce onu okumaya çalışırsanız genellikle bir derleme hatası verir (yerel değişkenler için). Bu, tanımsız değerlerle çalışmaktan kaynaklanan hataları önler.

2.2. Sabitler (Constants)

Değeri program boyunca asla değişmeyecek olan verileri tanımlamak için const anahtar kelimesi kullanılır. Sabitler bildirildikleri anda bir değerle başlatılmak zorundadır ve bu değer derleme zamanında biliniyor olmalıdır.

const double PI = 3.14159;
const int GUN_SAYISI = 7;
const string SITE_ADI = "BenimSitem.com";
// PI = 3.14; // Hata! Sabitin değeri değiştirilemez.
Sabitler, kodun okunabilirliğini artırır ve “sihirli sayıların” (kod içinde anlamı belirsiz sayısal değerlerin) kullanımını azaltır.

2.3. Veri Tiplerine Genel Bakış: Değer vs. Referans Tipleri

C#’taki veri tipleri, bellekte nasıl saklandıkları ve nasıl davrandıkları açısından iki ana kategoriye ayrılır. Bu ayrım C#’ın temelini anlamak için çok önemlidir:

Değer Tipleri (Value Types):
Değişkenleri doğrudan kendi değerlerini saklar.
Genellikle Stack adı verilen daha hızlı erişilen bir bellek bölgesinde tutulurlar (bazı istisnalar olabilir, örneğin bir sınıfın üyesi olan değer tipleri Heap’te o nesneyle birlikte saklanır).
Bir değer tipi değişkeni başka bir değişkene atandığında veya bir metoda parametre olarak geçirildiğinde, değerin tam bir kopyası oluşturulur (Pass-by-Value). Bir kopyada yapılan değişiklik diğerini etkilemez.
Yerleşik (built-in) sayısal tipler (int, float, double, decimal), bool, char, struct’lar ve enum’lar değer tipleridir.
Genellikle daha küçük boyutludurlar.
null değerini doğrudan alamazlar (Nullable Value Types hariç — Bölüm 6)
Referans Tipleri (Reference Types):
Değişkenleri doğrudan değeri değil, verinin bellekteki (genellikle Heap adı verilen daha büyük ama biraz daha yavaş erişilen bir bellek bölgesindeki) konumunu gösteren bir referansı (adresi) saklar.
Bir referans tipi değişkeni başka bir değişkene atandığında veya bir metoda parametre olarak geçirildiğinde, değerin kendisi değil, sadece bellekteki aynı nesneye işaret eden referans kopyalanır. Her iki değişken de aynı nesneye işaret eder.
Bir değişken üzerinden nesnede yapılan değişiklik, aynı nesneye işaret eden diğer değişken tarafından da görülür.
string, object, diziler (int[], string[] vb.), class ile tanımlanan tüm nesneler, interface’ler ve delegate’ler referans tipleridir.
null değerini alabilirler (yani hiçbir nesneyi işaret etmiyor olabilirler).
Bu farkı anlamak, özellikle metotlara parametre geçirme, atama işlemleri ve nesnelerin nasıl davrandığını anlamak için kritiktir.

Bölüm 3: Değer Tipleri (Value Types) Detaylı İnceleme

3.1. Tam Sayı Tipleri (Integral Types)

İşaretli (negatif değer alabilen) ve işaretsiz (sadece pozitif ve sıfır) tamsayıları temsil ederler. Farklı boyutlarda (bellekte kapladıkları alan) ve dolayısıyla farklı değer aralıklarında gelirler.

TürAçıklamaBoyut (Bytes)Aralık (Yaklaşık).NET Türüsbyteİşaretli 8-bit1–128 ile 127SBytebyteİşaretsiz 8-bit10 ile 255Byteshortİşaretli 16-bit2–32,768 ile 32,767Int16ushortİşaretsiz 16-bit20 ile 65,535UInt16intİşaretli 32-bit4–2.1 Milyar ile +2.1 MilyarInt32uintİşaretsiz 32-bit40 ile 4.2 MilyarUInt32longİşaretli 64-bit8–9 Kentilyon ile +9 KentilyonInt64ulongİşaretsiz 64-bit80 ile 18 KentilyonUInt64

Varsayılan: Tamsayı literalleri (örn. 10, 123) varsayılan olarak int kabul edilir. Daha büyük bir değer veya long kullanmak için L veya l soneki eklenir (örn. 12345678901L). uint veya ulong için U/u veya UL/ul sonekleri kullanılır.
Seçim: Genellikle çoğu tamsayı ihtiyacı için int yeterlidir. Çok büyük sayılar için long, negatif değer almayacak ve bellek/performansın kritik olduğu (veya belirli API’lerle uyum için) durumlarda byte veya ushort, veya 4 milyardan büyük pozitif sayılar için ulong kullanılabilir. İşaretsiz tipler (uint, ulong vb.) CLS (Common Language Specification) uyumlu değildir, yani diğer .NET dilleriyle etkileşimde sorun yaratabilirler, bu yüzden genellikle int ve long tercih edilir.
int kullaniciSayisi = 1500;
long dunyaNufusu = 8_000_000_000L; // Okunabilirlik için _ kullanılabilir
byte dosyaBayti = 255;
short kucukSayi = -1000;
uint pozitifLimit = 4_000_000_000;
3.2. Kayan Noktalı Sayı Tipleri (Floating-Point Types)

Ondalıklı sayıları temsil ederler. Hassasiyet ve aralık bakımından farklılık gösterirler.

TürAçıklamaBoyut (Bytes)Hassasiyet (Yaklaşık Ondalık Hane)Aralık (Yaklaşık).NET TürüSonekfloatTek duyarlı (Single-precision)46–9 hane±1.5e-45 ile ±3.4e38SingleF / fdoubleÇift duyarlı (Double-precision)815–17 hane±5.0e-324 ile ±1.7e308DoubleD / d (Varsayılan)

Varsayılan: Ondalıklı literaller (örn. 3.14, 10.0) varsayılan olarak double kabul edilir. float kullanmak için F veya f soneki eklenmelidir.
Hassasiyet: double, float’a göre daha fazla ondalık basamağı doğru bir şekilde saklayabilir ve daha geniş bir aralığa sahiptir.
Kullanım: Genel amaçlı ondalıklı sayılar için genellikle double tercih edilir. Bellek kısıtı olan veya 3D grafik gibi alanlarda bazen float kullanılabilir.
Dikkat: Kayan noktalı sayılar doğaları gereği (ikilik tabanda tam temsil edilememe nedeniyle) küçük hassasiyet hataları içerebilirler (0.1 + 0.2 == 0.3 ifadesi false olabilir). Para birimi gibi hassas ondalık hesaplamaları için KESİNLİKLE kullanılmamalıdırlar.
double ortalama = 85.75;
float yerCekimi = 9.81f; // 'f' soneki gerekli
double cokKucuk = 1.23e-15;
// Hassasiyet örneği
double d1 = 0.1;
double d2 = 0.2;
Console.WriteLine(d1 + d2); // 0.30000000000000004 gibi bir çıktı verebilir!
// Console.WriteLine(d1 + d2 == 0.3); // Muhtemelen False
3.3. decimal Tipi: Yüksek Hassasiyetli Ondalık

Amacı: Finansal ve parasal hesaplamalar gibi yüksek hassasiyet gerektiren ve kayan noktalı sayıların ikilik taban hatalarından etkilenmemesi gereken durumlar için özel olarak tasarlanmıştır.
Boyut: 16 byte.
Hassasiyet: 28–29 ondalık basamağa kadar çok yüksek hassasiyet sunar.
Aralık: double’a göre daha dardır, ancak ondalık hassasiyeti çok daha yüksektir.
Kullanım: Parasal değerler, muhasebe, bilimsel hesaplamalarda hassasiyetin kritik olduğu durumlar.
Literal Soneki: decimal literalleri için M veya m soneki kullanılır.
Performans: double veya float’a göre hesaplamaları biraz daha yavaştır, çünkü ikilik yerine onluk tabanda işlem yapar.
decimal paraMiktari = 1250.75m; // 'm' soneki gerekli
decimal vergiOrani = 0.18m;
decimal vergiTutari = paraMiktari * vergiOrani;
decimal toplamTutar = paraMiktari + vergiTutari;
Console.WriteLine($"Toplam Tutar: {toplamTutar:C}"); // Para birimi formatında yazdırır (kültüre göre)
// double ile karşılaştırma
double dPara = 1250.75;
double dVergiOrani = 0.18;
double dToplam = dPara * (1 + dVergiOrani);
Console.WriteLine($"Double ile Toplam: {dToplam}"); // Küçük farklar olabilir
Kural: Para ile ilgili tüm hesaplamalar için her zaman decimal kullanın.

3.4. bool Tipi: Mantıksal Değerler

Mantıksal true (doğru) veya false (yanlış) değerlerini temsil eder.
Koşullu ifadelerin (if, while), karşılaştırma operatörlerinin ve mantıksal operatörlerin temelini oluşturur.
Boyut: Mantıksal olarak 1 bit, ancak bellek hizalaması nedeniyle genellikle en az 1 byte yer kaplar.
.NET Türü: Boolean.
bool aktif = true;
bool yetkiliMi = false;
int sicaklik = 25;
bool havaSicak = sicaklik > 20; // Karşılaştırma sonucu bool olur (true)
3.5. char Tipi: Tek Karakterler

Tek bir Unicode karakterini temsil eder.
Değerler tek tırnak (‘ ‘) içine alınır.
Boyut: 2 byte (UTF-16 kodlaması kullanır).
.NET Türü: Char.
char harf = 'A';
char rakamKarakter = '7';
char sembol = '$';
char unicodeKarakter = '\u005A'; // 'Z' karakterinin Unicode kaçış sekansı
// Console.WriteLine(harf + rakamKarakter); // Sayısal ASCII/Unicode değerlerini toplar, dikkat! (112)
Console.WriteLine(harf); // A
Console.WriteLine((int)harf); // A'nın Unicode/ASCII değeri: 65
3.6. Yapılar (struct)

Yerleşik değer tipleri (int, bool, decimal vb.) aslında .NET’teki yapıların (structs) takma adlarıdır (alias). struct anahtar kelimesiyle kendi özel değer tiplerinizi de oluşturabilirsiniz. Struct’lar genellikle küçük, veri odaklı yapılar için kullanılır ve değer tipi semantiğine sahiptirler (kopyalanarak atanırlar/geçirilirler).

Bölüm 4: Referans Tipleri (Reference Types) Detaylı İnceleme

4.1. string Tipi: Metin Dizileri

Bir karakter dizisini temsil eder.
Değerler çift tırnak (“ “) içine alınır.
C#’ta string referans tipidir, yani değişkenler string’in bellekteki konumuna bir referans tutar.
ANCAK: String’ler değişmezdir (immutable). Bir string oluşturulduktan sonra içeriği değiştirilemez. String üzerinde yapılan işlemler (birleştirme, alt string alma, harf değiştirme vb.) her zaman yeni bir string nesnesi oluşturur. Bu, bellek yönetimi ve bazı performans durumları açısından önemlidir.
.NET Türü: String.
null olabilir.
string mesaj = "Merhaba C#";
string bos = "";
string nullString = null;
// Birleştirme
string tamAd = "Ali" + " " + "Can"; // Yeni bir string oluşturur
// İmmutability Örneği
string s1 = "İlk";
string s2 = s1; // s2 de aynı "İlk" string'ine referans verir
s1 = s1 + " Kısım"; // YENİ bir string ("İlk Kısım") oluşturulur ve s1 ona referans verir.
// s2 hala orijinal "İlk" string'ine referans verir.
Console.WriteLine(s1); // İlk Kısım
Console.WriteLine(s2); // İlk
// String Metotları (Yeni string döndürürler)
string kucukHarf = mesaj.ToLower(); // "merhaba c#"
string buyukHarf = mesaj.ToUpper(); // "MERHABA C#"
string parca = mesaj.Substring(8, 2); // "C#"
bool iceriyorMu = mesaj.Contains("C#"); // true
string degistir = mesaj.Replace("C#", ".NET"); // "Merhaba .NET"
Console.WriteLine(mesaj); // "Merhaba C#" (Orijinal değişmedi)
Verbatim String Literals (@): Başına @ konulan string’lerde kaçış karakterleri (\n, \t, \) işlenmez ve string birden fazla satıra yayılabilir. Dosya yolları veya uzun metinler için kullanışlıdır.

string dosyaYolu = @"C:\Kullanicilar\Ahmet\Belgelerim\rapor.txt";
string cokSatirli = @"Bu birinci satır.
Bu ikinci satır.
Girintili satır.";
Interpolated Strings ($ — C# 6+): String içine değişken veya ifade değerlerini {} kullanarak kolayca gömmeyi sağlar. Template Literals’a benzer.

string adInterpol = "Veli";
int yasInterpol = 40;
string mesajInterpol = $"Kullanıcı Adı: {adInterpol}, Yaş: {yasInterpol}, Emekliliğe Kalan Yıl: {65 - yasInterpol}";
Console.WriteLine(mesajInterpol); // Kullanıcı Adı: Veli, Yaş: 40, Emekliliğe Kalan Yıl: 25
4.2. object Tipi: Evrensel Temel Tip

.NET’teki tüm türlerin (hem değer hem referans tiplerinin) türediği nihai temel sınıftır.
Bu nedenle, bir object türündeki değişken herhangi bir türdeki değeri tutabilir.
.NET Türü: Object.
null olabilir.
Boxing ve Unboxing:

Bir değer tipinin (örn. int) bir object değişkenine atanması işlemine boxing (kutulama) denir. Değer, Heap’te yeni bir nesne içine sarmalanır ve referansı object değişkenine atanır.
Bir object değişkenindeki (aslında kutulanmış bir değer tipi içeren) değeri geri orijinal değer tipine dönüştürme işlemine unboxing (kutudan çıkarma) denir. Bu işlem açık tür dönüşümü (explicit cast) gerektirir ve tür uyumsuzsa çalışma zamanı hatası (InvalidCastException) verir.
object obj1 = 10; // Boxing (int -> object)
object obj2 = "Merhaba"; // Referans ataması (string zaten referans tipi)
object obj3 = true; // Boxing (bool -> object)
object obj4 = new List(); // Referans ataması
// Unboxing (Dikkatli yapılmalı!)
int sayi = (int)obj1; // Unboxing (object -> int)
Console.WriteLine(sayi * 2); // 20
// Hatalı Unboxing
try
{
string strHata = (string)obj1; // InvalidCastException (obj1 int içeriyor, string değil)
}
catch (InvalidCastException e)
{
Console.WriteLine("Unboxing hatası: " + e.Message);
}
object türü esneklik sağlasa da, boxing/unboxing performans maliyeti getirir ve tür güvenliğini azaltır. Genellikle generic’ler (List) veya belirli türler kullanmak daha iyidir.

4.3. Diziler (Arrays)

Aynı türden sabit sayıda öğeyi sıralı bir şekilde saklayan koleksiyonlardır.
Referans tipleridir.
new anahtar kelimesi ve boyut belirtilerek veya dizi literali ile oluşturulurlar.
int[] sayiDizisi = new int[5]; // 5 elemanlık int dizisi (elemanlar varsayılan 0 ile başlar)
string[] isimler = { "Ayşe", "Fatma", "Hayriye" }; // Dizi literali
sayiDizisi[0] = 10;
Console.WriteLine(isimler[1]); // Fatma
Diziler ayrı bir konu olarak daha detaylı incelenir.

4.4. Sınıflar (Classes)

class anahtar kelimesiyle tanımlanan özel türlerdir. Nesne Yönelimli Programlamanın temelini oluştururlar ve veri (alanlar, özellikler) ile davranışı (metotlar) birleştirirler. Sınıflar her zaman referans tipleridir.

4.5. Diğer Referans Tipleri: interface, delegate, record (C# 9+).

Bölüm 5: Tür Dönüşümleri (Type Conversions / Casting)

Bir türdeki veriyi başka bir türe dönüştürme işlemidir.

5.1. Örtük Dönüşüm (Implicit Conversion):

Derleyici tarafından otomatik ve güvenli bir şekilde yapılır.
Veri kaybı riski olmayan dönüşümlerdir (genellikle daha küçük bir türden daha büyük bir türe).
Örnek: int’ten long’a, int’ten double’a, byte’tan int’e.
int kucukSayiConv = 100;
long buyukSayiConv = kucukSayiConv; // Örtük dönüşüm (int -> long) - Güvenli
double ondalikliSayi = kucukSayiConv; // Örtük dönüşüm (int -> double) - Güvenli
Console.WriteLine(ondalikliSayi); // 100.0
5.2. Açık Dönüşüm (Explicit Conversion / Casting):

Veri kaybı riski taşıyan veya derleyicinin otomatik yapamayacağı dönüşümlerdir.
Programcının bilinçli olarak yapması gerekir.
Cast Operatörü (dataType): Parantez içinde hedef tür belirtilerek yapılır. Eğer dönüşüm geçersizse çalışma zamanı hatası (InvalidCastException) fırlatabilir.
Convert Sınıfı: Farklı türler arasında dönüşüm yapmak için statik metotlar sunar (Convert.ToInt32(), Convert.ToString(), Convert.ToDouble() vb.). Dönüşüm mümkün değilse hata fırlatır. null değerler için genellikle varsayılan değer (örn. 0) döndürür.
Parse() / TryParse() Metotları: Genellikle string’leri sayısal veya boolean gibi diğer türlere dönüştürmek için kullanılır (örn. int.Parse(), double.Parse(), bool.Parse()).
Parse(): Dönüşüm başarısız olursa FormatException fırlatır.
TryParse(): Dönüşümün başarılı olup olmadığını boolean olarak döndürür ve sonucu bir out parametresi ile verir. Hata fırlatmaz, bu nedenle genellikle daha güvenlidir.
double ondalikli = 9.78;
// int tamSayi = ondalikli; // Hata! Örtük dönüşüm yok.
// Cast Operatörü ile Açık Dönüşüm
int tamSayiCast = (int)ondalikli; // Ondalık kısım atılır (veri kaybı!)
Console.WriteLine(tamSayiCast); // 9
long cokBuyuk = 10000000000L;
// int sigmayan = (int)cokBuyuk; // Hata veya beklenmedik değer (veri kaybı/taşma!)
// Convert Sınıfı
string sayiStr = "123";
int sayiConvert = Convert.ToInt32(sayiStr);
Console.WriteLine(sayiConvert * 2); // 246
string boolStr = "true";
bool boolConvert = Convert.ToBoolean(boolStr);
Console.WriteLine(boolConvert); // True
object objSayi = 456;
int sayiUnboxConvert = Convert.ToInt32(objSayi); // Unboxing için de kullanılabilir
// Parse / TryParse
string input = "45b"; // Geçersiz sayı
int sonucParse;
// int hataParse = int.Parse(input); // FormatException fırlatır!
if (int.TryParse(input, out sonucParse))
{
Console.WriteLine("Parse Başarılı: " + sonucParse);
}
else
{
Console.WriteLine("Geçersiz sayı formatı: " + input); // Bu çalışır
}
if (int.TryParse("999", out sonucParse))
{
Console.WriteLine("Parse Başarılı: " + sonucParse); // Bu çalışır (999)
}
Bölüm 6: Nullable Değer Tipleri (?)

Değer tipleri (int, bool, struct vb.) normalde null değeri alamazlar. Ancak bazen bir değer tipinin “değer yok” durumunu temsil etmesi gerekebilir (örn. veritabanından gelen isteğe bağlı bir alan). Bu durumlar için nullable değer tipleri kullanılır.

Söz Dizimi: Değer tipinin sonuna ? eklenir (int?, double?, bool?, DateTime?).
Temel Tür: Aslında System.Nullable generic yapısının bir kısayoludur (int? aslında Nullable’dir).
Özellikler:
Normal değerini veya null değerini tutabilir.
HasValue (bool): Değişkenin null olmayan bir değere sahip olup olmadığını döndürür.
Value (T): Eğer HasValue true ise, değişkenin değerini döndürür. HasValue false iken erişilmeye çalışılırsa InvalidOperationException fırlatır.
Null-Coalescing Operatörü (??): Nullable bir değişken null ise, varsayılan bir değer atamak için kullanılır. nullableDegisken ?? varsayilanDeger.
int? sayiNullable = null; // Geçerli
double? oranNullable = 3.14;
bool? secimNullable = true;
Console.WriteLine($"Sayı: {sayiNullable}, Oran: {oranNullable}, Seçim: {secimNullable}");
sayiNullable = 10;
if (sayiNullable.HasValue)
{
Console.WriteLine("Sayı Değeri: " + sayiNullable.Value); // 10
} else {
Console.WriteLine("Sayı null.");
}
// Value'ya güvenli erişim
int sonuc = sayiNullable.GetValueOrDefault(); // Varsa değeri, yoksa türün varsayılanını (int için 0) döner
int sonucVarsayilan = sayiNullable.GetValueOrDefault(-1); // null ise -1 döner
// Null-Coalescing Operatörü
int garantiSayi = sayiNullable ?? -1; // sayiNullable null değilse değerini (10), null ise -1'i ata.
Console.WriteLine(garantiSayi); // 10
int? nullSayi = null;
int garantiSayi2 = nullSayi ?? 0; // nullSayi null olduğu için 0 atanır.
Console.WriteLine(garantiSayi2); // 0
Bölüm 7: var Anahtar Kelimesi — Örtük Tip Tanımlama (Implicit Typing)

C# 3.0 ile gelen var anahtar kelimesi, yerel değişkenlerin türünü açıkça belirtmek yerine, derleyicinin atanan değere bakarak türü otomatik olarak çıkarmasına olanak tanır.

Önemli: Bu, JavaScript’teki gibi dinamik tipleme değildir! var ile tanımlanan değişkenin türü derleme zamanında belirlenir ve daha sonra değiştirilemez. var sadece bir söz dizimi kolaylığıdır.

var sayacVar = 10; // Derleyici bunun int olduğunu anlar
var mesajVar = "Merhaba"; // Derleyici bunun string olduğunu anlar
var listeVar = new List(); // Derleyici bunun List olduğunu anlar
var aktifVar = true; // Derleyici bunun bool olduğunu anlar
// sayacVar = "Deneme"; // Hata! Tür derleme zamanında int olarak belirlendi, string atanamaz.
// Ne zaman kullanılır?
// - Tür adı çok uzun ve tekrarlı olduğunda (örn. Dictionary> gibi)
var kullaniciAyarlari = new Dictionary();
// - LINQ sorguları gibi anonim türler döndüren ifadelerde
// var sonucSorgu = from cust in musteriler where cust.Sehir == "Ankara" select new { cust.Ad, cust.Telefon };
// Ne zaman kaçınılmalı?
// - Tür hemen anlaşılamıyorsa veya kodun okunabilirliğini azaltıyorsa
var sonuc = GetMagicNumber(); // GetMagicNumber ne döndürüyor? int? double? decimal? Belirsiz!
int sonucExplicit = GetMagicNumber(); // Daha açık
// - Özellikle sayısal türlerde (int, double, float, decimal) belirsizlik yaratıyorsa
var fiyatVar = 10.5; // Bu double mı? decimal mı? (Varsayılan double)
decimal fiyatDec = 10.5m; // Açıkça decimal
// Genel Kural: 'var' kodun okunabilirliğini artırıyorsa kullanın, azaltıyorsa açık tür belirtin.
Bölüm 8: Sonuç — Sağlam Temeller

C#’ın temel söz dizimi ve veri tipleri, dilin güçlü, güvenli ve yapılandırılmış doğasının temelini oluşturur. Noktalı virgüller, blok yapıları, büyük/küçük harf duyarlılığı gibi temel kurallar kodun tutarlılığını sağlarken, namespace, class ve Main metodu gibi yapılar programın organizasyonunu belirler.

C#’ın en önemli özelliklerinden biri güçlü tipli olmasıdır. Değer Tipleri (sayısal türler, bool, char, struct) ve Referans Tipleri (string, object, array, class) arasındaki farkları (bellek yönetimi, atama/geçirme davranışı) anlamak, C# kodunun nasıl çalıştığını kavramak için kritiktir. int, double, decimal, bool, string gibi yerleşik tiplerin özelliklerini ve kullanım alanlarını bilmek, doğru veri yapılarını seçmenize yardımcı olur.

Tür dönüşümlerini (örtük ve açık casting, Convert, Parse/TryParse) doğru bir şekilde yönetmek, veri kaybını ve çalışma zamanı hatalarını önler. Nullable değer tipleri (?), değer tiplerine null atanabilirlik kazandırarak veritabanı ve API etkileşimlerini kolaylaştırır. var anahtar kelimesi ise, türü derleyici tarafından belirlenen yerel değişkenler tanımlayarak kodu kısaltabilir, ancak okunabilirlik pahasına kullanılmamalıdır.

Bu temel söz dizimi ve veri tipi bilgisi, C# ile daha karmaşık konulara (operatörler, kontrol akışı, metotlar, nesne yönelimli programlama, LINQ, asenkron işlemler vb.) geçiş yapmak için sağlam bir zemin oluşturur. Bu temellere hakim olmak, etkili ve güvenilir C# uygulamaları geliştirmenin ilk ve en önemli adımıdır.

Abdulkadir Güngör - Kişisel WebSite
Abdulkadir Güngör - Kişisel WebSite
Abdulkadir Güngör - Özgeçmiş
Github
Github
Linkedin