Mert Özen Her Satırda Daha İleri
Backend C# Temelleri — #03

C# Değişkenler ve Veri Tipleri: var, const ve Literal'ler

Mert Özen 7 Kas 2026 9 dk 1 görüntülenme
C# Değişkenler ve Veri Tipleri: var, const ve Literal'ler

C#'ta statik tipli değişkenler, hazır tiplerin boyutları ve aralıkları, var'ın gerçekte ne yaptığı, literal sonekleri ve derleyici hataları, const ve C# 10'un sabit interpolated string'i, varsayılan değerler ve .NET isimlendirme gelenekleri.

Sürüm notu: Bu yazıdaki kodlar C# 10 ve .NET 6 API'leriyle yazılmıştır; .NET 10 SDK ile derlenip denenmiştir.

Önce Tahmin Et

Altı değişken, hepsi var ile tanımlanmış. Sağ taraftaki değerler birbirine çok benziyor; bazılarının sonunda tek bir harf fark var. Program her değişkenin tipinin adını yazdırıyor. İki satırlık çıktıyı tahmin et:

var a = 42;
var b = 42L;
var c = 4.2;
var d = 4.2m;
var e = 'x';
var f = "x";

Console.WriteLine($"{a.GetType().Name} {b.GetType().Name} {c.GetType().Name}");
Console.WriteLine($"{d.GetType().Name} {e.GetType().Name} {f.GetType().Name}");
Int32 Int64 Double
Decimal Char String

Altı farklı tip. 42 bir int, sonuna L eklenince long oluyor. 4.2 bir double, m eklenince decimal. Tek tırnak bir karakter, çift tırnak bir string. var burada hiçbir tipi "seçmedi"; tipi sağ taraftaki değer belirledi. Bu yazıda C#'ta bir değişkenin tipinin nereden geldiğini, hazır tipleri, literal'leri, const'u ve isimlendirme kurallarını görüyoruz.

Değişken: Etiketli Bir Kutu

Değişken, bellekte bir değeri tutan ve ismi olan bir yer. Bir kutu düşün: üzerinde bir etiket (isim) var ve sadece belli şekildeki eşyalar (tip) içine sığıyor. C#'ta bir değişken tanımlarken önce tipi, sonra ismi yazarsın; istersen aynı satırda ilk değeri de verirsin:

int itemsInCart = 3;
itemsInCart = itemsInCart + 2;

C# statik tipli bir dil: bir değişkenin tipi compile time'da belli olur ve bir daha değişmez. Kutuya başka şekilde bir eşya koymaya çalışırsan compiler seni durdurur. var stock = 10; yazıp bir alt satırda stock = "ten"; dediğinde aldığın hata:

Program.cs(1,25): error CS0029: Cannot implicitly convert type 'string' to 'int'

JavaScript ya da Python'dan geliyorsan bu ilk başta kısıtlayıcı gelebilir. Ama aynı kısıtlama, büyük bir projede "bu değişkende ne var?" sorusunun cevabını her zaman bilmeni sağlar. Hatayı uygulama çalışırken müşterinin ekranında değil, derleme sırasında senin ekranında görürsün.

Bir diğer kural: bir yerel değişkeni değer vermeden okuyamazsın. int stock; yazıp hemen Console.WriteLine(stock); dersen compiler error CS0165: Use of unassigned local variable 'stock' der. Compiler, değişkene okunmadan önce her yolda bir değer atandığından emin olmak ister.

Hazır Tipler

C#'ın keyword'le yazılan hazır tipleri, önceki yazılarda gördüğümüz gibi .NET tiplerinin kısa adları: int aslında System.Int32, string aslında System.String. Sayısal tiplerin bellekte kapladığı yeri ve alabileceği değer aralığını programın kendisine sorduk:

using System.Globalization;

CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;

Console.WriteLine($"byte    {sizeof(byte),2} bytes  {byte.MinValue} .. {byte.MaxValue}");
Console.WriteLine($"short   {sizeof(short),2} bytes  {short.MinValue} .. {short.MaxValue}");
Console.WriteLine($"int     {sizeof(int),2} bytes  {int.MinValue} .. {int.MaxValue}");
Console.WriteLine($"long    {sizeof(long),2} bytes  {long.MinValue} .. {long.MaxValue}");
Console.WriteLine($"float   {sizeof(float),2} bytes  {float.MinValue} .. {float.MaxValue}");
Console.WriteLine($"double  {sizeof(double),2} bytes  {double.MinValue} .. {double.MaxValue}");
Console.WriteLine($"decimal {sizeof(decimal),2} bytes  {decimal.MinValue} .. {decimal.MaxValue}");
Console.WriteLine($"char    {sizeof(char),2} bytes  {(int)char.MinValue} .. {(int)char.MaxValue}");
Console.WriteLine($"bool    {sizeof(bool),2} bytes  {false} / {true}");
byte     1 bytes  0 .. 255
short    2 bytes  -32768 .. 32767
int      4 bytes  -2147483648 .. 2147483647
long     8 bytes  -9223372036854775808 .. 9223372036854775807
float    4 bytes  -3.4028235E+38 .. 3.4028235E+38
double   8 bytes  -1.7976931348623157E+308 .. 1.7976931348623157E+308
decimal 16 bytes  -79228162514264337593543950335 .. 79228162514264337593543950335
char     2 bytes  0 .. 65535
bool     1 bytes  False / True

İlk iki satır sayıların ekrana yazılma biçimini culture'dan bağımsız yapıyor; Türkçe ayarlı bir bilgisayarda ondalık ayırıcı virgül olur ve çıktı farklı görünür. Culture konusunu string'ler ve tip dönüşümleri yazılarında açacağız.

Günlük işlerin çoğunda şu tiplerle yetinirsin: tam sayılar için int, int'e sığmayacak büyüklükte sayılar için long, ondalıklı ölçümler için double, para için decimal, evet/hayır için bool, metin için string. char tek bir UTF-16 karakteri tutar, bu yüzden 2 byte. Bunların işaretsiz kardeşleri de var: sbyte, ushort, uint, ulong; ama uygulama kodunda nadiren gerekir. Sayısal tiplerin farklarını, özellikle double ile decimal arasındaki farkı bir sonraki yazıda ayrıntılı göreceğiz.

Bu tiplerle kitapçımızdaki bir kitabı şöyle anlatabiliriz:

using System.Globalization;

CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;

string title = "Clean Code";
string isbn = "978-0132350884";
int pageCount = 464;
decimal price = 34.90m;
double rating = 4.7;
bool inStock = true;
char shelf = 'C';
long totalSold = 1_250_000L;

Console.WriteLine($"{title} ({isbn})");
Console.WriteLine($"{pageCount} pages, {price} USD, rating {rating}");
Console.WriteLine($"In stock: {inStock}, shelf {shelf}, sold {totalSold}");
Clean Code (978-0132350884)
464 pages, 34.90 USD, rating 4.7
In stock: True, shelf C, sold 1250000

ISBN'in string olduğuna dikkat et. İçinde rakamlar var ama onunla hesap yapmayacaksın; tire içerir ve başındaki sıfırların kaybolmaması gerekir. Telefon numarası, posta kodu ve TC kimlik numarası gibi değerler de aynı sebeple sayı değil metin olarak tutulur.

var: Tipi Compiler Bulur

var, "bu değişkenin tipini sağ taraftaki değerden sen çıkar" demek. Önce Tahmin Et'te gördüğün gibi var a = 42; ile int a = 42; arasında derlenmiş kodda hiçbir fark yok. var dinamik bir tip değil; tip yine compile time'da belirlenir ve sabit kalır. Bu yüzden var'ın iki şartı var: değişkene tanımlandığı satırda değer vermelisin ve o değerin bir tipi olmalı.

Program.cs(1,5): error CS0818: Implicitly-typed variables must be initialized
Program.cs(1,5): error CS0815: Cannot assign <null> to an implicitly-typed variable

İlki var stock;, ikincisi var title = null; satırından geliyor. null'ın kendi başına bir tipi olmadığı için compiler neyi kastettiğini bilemez.

Ne zaman var? Genel kural şu: tip sağ tarafa bakınca hemen anlaşılıyorsa var okunabilirliği artırır, anlaşılmıyorsa açık tip yaz. var builder = new StringBuilder(); satırında tip zaten sağda yazıyor. var total = Calculate(); satırında ise okuyan kişi method'a gitmeden tipi bilemez; decimal total = Calculate(); çok daha net. Yeni başlarken açık tip yazmayı alışkanlık hâline getirmeni öneririm: hangi değerin hangi tipte olduğunu düşünmek, bu serinin ilk yazılarının asıl kazancı.

Literal'ler

Kodun içine doğrudan yazdığın değerlere literal denir: 42, 4.2, 'x', "Clean Code", true. Her literal'in bir tipi vardır ve sonuna eklediğin harf bu tipi değiştirir:

int plain = 255;
int hex = 0xFF;
int binary = 0b1111_1111;
long population = 85_000_000L;
uint positiveOnly = 42u;
float ratio = 0.75f;
double average = 0.75;
decimal discount = 0.75m;
char letter = 'A';
char tab = '\t';

Console.WriteLine(plain == hex && hex == binary);
Console.WriteLine($"{population} {positiveOnly} {letter}{tab}{letter}");
Console.WriteLine($"{ratio.GetType().Name} {average.GetType().Name} {discount.GetType().Name}");
True
85000000 42 A	A
Single Double Decimal

Aynı sayıyı onluk, onaltılık (0x) ve ikilik (0b) yazabilirsin; üçü de 255. Alt çizgi sadece okunabilirlik için, compiler onu yok sayar: 85_000_000 ile 85000000 aynı şey. float'un .NET'teki adının Single olduğuna da dikkat et.

Sonek unutulduğunda compiler seni uyarmakla kalmaz, ne yapman gerektiğini de söyler. decimal price = 34.90; yazdığında:

Program.cs(1,17): error CS0664: Literal of type double cannot be implicitly converted to type 'decimal'; use an 'M' suffix to create a literal of this type

Sebebi şu: 34.90 bir double literal'i ve double'dan decimal'e sessiz bir dönüşüm yok. Aynı şey float için de geçerli, orada istenen sonek F. Tam sayılarda ise literal'in tipi büyüklüğüne göre seçilir: int'e sığmayan 3_000_000_000 bir uint olur ve int big = 3_000_000_000; satırı error CS0266: Cannot implicitly convert type 'uint' to 'int' verir. Aralık dışı bir değer de derlenmez: byte b = 256; için error CS0031: Constant value '256' cannot be converted to a 'byte'.

const: Değişmeyen Değerler

Değeri program boyunca hiç değişmeyecek bir şey için const kullanırsın. Bir sepetin alabileceği en fazla ürün sayısı ya da mağazanın adı gibi:

const int MaxCartItems = 20;
const string StoreName = "Bookstore";
const string Greeting = $"Welcome to {StoreName}";

int itemsInCart = 3;
itemsInCart = itemsInCart + 2;

Console.WriteLine(Greeting);
Console.WriteLine($"{itemsInCart} of {MaxCartItems} items");
Welcome to Bookstore
5 of 20 items

const'un değeri compile time'da bilinmek zorunda, çünkü compiler onu kullanıldığı her yere doğrudan yazar. Greeting satırı C# 10 ile gelen bir kolaylık: parçaları sabit string'lerden oluşan bir interpolated string artık const olabiliyor. Ama const int Length = Title.Length; derlenmez, çünkü Length runtime'da hesaplanan bir property: error CS0133: The expression being assigned to 'Length' must be constant. Bir const'a sonradan değer atamaya çalışırsan da error CS0131: The left-hand side of an assignment must be a variable, property or indexer alırsın.

Ne zaman const? Kodda aynı sayı birden fazla yerde geçiyorsa ve bir anlamı varsa ona bir isim ver. if (itemsInCart > 20) yerine if (itemsInCart > MaxCartItems) yazdığında kod kendini anlatır ve sınır değiştiğinde tek bir satırı güncellersin.

Varsayılan Değerler

Yerel değişkenlere değer vermeden okuyamadığını gördük. Ama array element'leri ve class'ların field'ları gibi yerler otomatik olarak tipin varsayılan değeriyle başlar. Sayılar için 0, bool için false, char için '\0', string gibi reference type'lar için null:

int[] stocks = new int[3];
bool[] flags = new bool[2];
string[] titles = new string[2];

Console.WriteLine(stocks[0]);
Console.WriteLine(flags[1]);
Console.WriteLine(titles[0] is null);
Console.WriteLine(default(decimal));
Console.WriteLine(default(char) == '\0');
0
False
True
0
True

default(T) expression'ı herhangi bir tipin varsayılan değerini verir. Array'leri ve null'ı kendi yazılarında ayrıntılı göreceğiz. Şimdilik şunu bil: string title = default; yazdığında, nullable açık bir projede compiler warning CS8600: Converting null literal or possible null value to non-nullable type. uyarısını verir. Bu uyarı "bu string'in null olmayacağını söyledin ama ona null verdin" demek.

İsimlendirme Kuralları

Bir isim harf ya da alt çizgiyle başlar, rakamla başlayamaz. Keyword'leri isim olarak kullanamazsın: string class = "fiction"; bir dizi syntax hatası üretir. Gerçekten gerekirse başına @ koyarsın (@class) ama bu genellikle başka bir dille konuşan kodda gerekir. C# büyük-küçük harfe duyarlı: pageCount tanımlayıp PageCount kullanırsan error CS0103: The name 'PageCount' does not exist in the current context alırsın.

Kurallar bir yana, .NET dünyasının yerleşik alışkanlıkları da var. Yerel değişkenler ve parametreler camelCase: pageCount, itemsInCart. Tip adları, method'lar, property'ler ve const'lar PascalCase: MaxCartItems, StoreName. Private field'larda yaygın gelenek alt çizgi ile camelCase: _stock. İsimler kısaltma yerine anlam taşısın: p değil price, cnt değil count. Kod bir kez yazılır, onlarca kez okunur.

Sık Düşülen Tuzaklar

Para için double kullanmak. double price = 34.90; derlenir ve ilk bakışta doğru çalışır. Sorun toplamalar ve yuvarlamalarla ortaya çıkar; bir sonraki yazıda bunu sayılarla göreceğiz. Fiyat, tutar, bakiye gibi değerler için decimal ve m soneki.

var'ı dinamik tip sanmak. var ile tanımladığın değişkene sonradan başka tipte bir değer atayamazsın. var yazmak tipi kaldırmaz, sadece yazmayı compiler'a bırakır.

Numara gibi görünen her şeyi sayı yapmak. ISBN, telefon, posta kodu gibi değerlerle aritmetik yapılmaz. Bunları int ya da long yaparsan baştaki sıfırları ve tireleri kaybedersin.

Sihirli sayılar. Kodun ortasına gömülü 20, 0.18, 365 gibi sayılar bir süre sonra kimsenin anlamını bilmediği değerlere dönüşür. Anlamı olan sayıya const ile bir isim ver.

Küçük Bir Deneme

★☆☆ Önce Tahmin Et'teki programa var g = 42u;, var h = 4.2f; ve var i = true; satırlarını ekle, tiplerini tahmin et ve çalıştırarak kontrol et.

★★☆ Kitap örneğine yazarın adı, basım yılı ve indirimde olup olmadığı için birer değişken ekle. Her biri için hangi tipi seçtiğini ve neden seçtiğini bir yorum satırıyla yaz.

★★★ long totalSold = 1_250_000L; satırını int yap ve değeri 3_000_000_000 olarak değiştir. Hangi hata kodunu alıyorsun? Sonra long'a geri dön ama L sonekini sil; derlenir mi, neden?

Değişkenleri ve tipleri tanıdık. Bir sonraki yazıda sayılarla gerçekten hesap yapıyoruz: int, long, double ve decimal arasındaki farklar, tamsayı bölmesinin sürprizleri, overflow ve checked, Math class'ı ve 0.1 + 0.2'nin neden 0.3 etmediği.