C# System.FormatException hatası, kullanıcıdan alınan sayı veya tarih metni beklenen biçime uymadığında ortaya çıkabilir. Çözüm için kullanıcı girdisini doğrudan Parse ile dönüştürmek yerine önce TryParse ile doğrulamak, ardından hedef veri türüne ve kültür ayarlarına uygun biçimi kullanmak gerekir. Dönüşüm başarısız olduğunda TryParse çoğu standart kullanımda istisna fırlatmak yerine false döndürür.
Hatanın kaynağını bulurken yalnızca ondalık ayırıcıya odaklanma. Geçersiz karakterler, desteklenmeyen tarih biçimleri, sayının hedef türün aralığını aşması ve null değer birbirinden farklı durumlardır.
System.FormatException neden oluşur?

FormatException, metnin beklenen veri biçimine dönüştürülememesi durumunda oluşur. Örneğin int.Parse("42x") çağrısında metin, tam sayı için beklenen biçime uymaz. Benzer şekilde tarih dönüşümünde geçerli bir tarih ve saat gösterimi olmayan metin de FormatException oluşturabilir. Parse yöntemleri, dönüşüm başarısızlığını istisna ile bildirirken TryParse yaklaşımı kullanıcı girdisini önce kontrol etmene olanak tanır.
Bu istisnayı diğer dönüşüm sorunlarıyla karıştırmamak gerekir. Örneğin Int32.Parse için null giriş ArgumentNullException, biçime uymayan metin FormatException, Int32 aralığının dışındaki sayı ise OverflowException ile ilişkilidir. Hangi istisnanın oluşacağı kullanılan yönteme ve çağrılan aşırı yüke göre değişebilir. NumberStyles, IFormatProvider veya tarih biçimi gibi seçenekler, kabul edilen metin biçimini etkileyebilir.
Kültür uyuşmazlığı özellikle ondalık sayılarda ve tarihlerde sık karşılaşılan bir nedendir, ancak tek neden değildir. Örneğin 12,50 metninin nasıl yorumlanacağı seçilen kültüre bağlı olabilir. Bunun yanında girdinin başında veya sonunda görünmeyen boşluklar, harf içeren bir sayı, yanlış hedef tür seçimi ya da geçersiz bir tarih bileşeni de dönüşümü bozabilir.
Hatalı dönüşümü adım adım nasıl teşhis edersin?
Hata mesajı tek başına kök nedeni her zaman göstermez. Dönüşüm satırını, gerçek girdiyi, hedef veri türünü ve kullanılan kültürü birlikte incelemek daha sağlıklı bir teşhis sağlar. Aşağıdaki kontrol listesi, konsol veya masaüstü uygulamasındaki kullanıcı girdilerini incelerken kullanılabilir.
Beş adımlı kontrol listesi
- Dönüşüm satırını bul. İstisnanın oluştuğu satırı ve çağrılan yöntemi belirle.
int.Parse,decimal.Parse,DateTime.Parseveya daha özel bir aşırı yük kullanılıp kullanılmadığını kontrol et. - Girdinin gerçek içeriğini incele. Değeri köşeli ayraçlarla görüntülemek, başta ve sonda boşluk olup olmadığını fark etmeyi kolaylaştırır. Metnin uzunluğunu da kontrol et. Ekranda doğru görünen bir değer, farklı bir boşluk karakteri içerebilir.
- Hedef veri türünü netleştir. Girdi tam sayı mı, ondalıklı sayı mı, yoksa tarih mi olmalı? Tam sayı beklenen bir alanda ondalık bölüm bulunması veya sayı aralığının hedef türü aşması farklı bir soruna işaret eder.
- Beklenen biçimi yazılı hâle getir. Ondalık ayırıcının virgül mü nokta mı olduğunu, binlik ayırıcıya izin verilip verilmediğini ve tarih alanında gün, ay, yıl sırasının nasıl olması gerektiğini belirle.
- Kültür ve biçim ayarlarını incele.
Parseya daTryParseçağrısında hangi kültürün ve stil seçeneklerinin kullanıldığını kontrol et. Sabit bir tarih biçimi bekleniyorsa genel ayrıştırma yerine uygun bir kesin biçim yöntemi değerlendirilebilir.
Aşağıdaki küçük örnekte girdi, dönüşümden önce görünür hâle getirilir ve geçerli olup olmadığı kontrol edilir:
using System;
class Program
{
static void Main()
{
string input = " 42 ";
Console.WriteLine($"Girdi: [{input}]");
Console.WriteLine($"Karakter sayısı: {input.Length}");
if (int.TryParse(input, out int number))
Console.WriteLine($"Sayı: {number}");
else
Console.WriteLine("Geçersiz sayı");
}
}
Beklenen çıktı şöyledir:
Girdi: [ 42 ]
Karakter sayısı: 4
Sayı: 42
Gerçek uygulamada teşhis amacıyla girdi kaydı tutarken parola, kimlik numarası veya benzeri hassas verileri gereksiz yere saklama. Gerekirse değeri maskeleyerek yalnızca biçim, uzunluk, hedef tür ve dönüşüm sonucunu kaydet.
TryParse ile sayı ve tarih girdisi nasıl doğrulanır?

Kullanıcıdan gelen sayısal veya tarih metnini doğrudan Parse ile dönüştürmek yerine, önce TryParse ya da kesin biçim gerekiyorsa TryParseExact kullan. Bu yöntemler dönüşümün başarılı olup olmadığını bool ile bildirir. Böylece hatalı metni FormatException beklemeden doğrulama akışına alabilirsin.
decimal.TryParse için sayı stili, kültür ve sonuç parametrelerini birlikte belirleyebilirsin. Aşağıdaki örnekte NumberStyles.AllowDecimalPoint seçildi ve AllowThousands eklenmedi. Böylece nokta veya virgülün binlik ayırıcı olarak sessizce kabul edilmesi önlenir. Yöntemin ilgili aşırı yükünü Microsoft Learn Decimal.TryParse dokümantasyonunda inceleyebilirsin.
using System;
using System.Globalization;
string[] inputs = { "12,5", "12.5", "abc" };
foreach (string input in inputs)
{
ShowNumber(input, "tr-TR", CultureInfo.GetCultureInfo("tr-TR"));
ShowNumber(input, "Invariant", CultureInfo.InvariantCulture);
}
string[] dateInputs = { "2024-09-24", "24.09.2024" };
foreach (string dateText in dateInputs)
{
bool valid = DateTime.TryParseExact(
dateText,
"yyyy-MM-dd",
CultureInfo.InvariantCulture,
DateTimeStyles.None,
out DateTime date);
string result = valid
? date.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture)
: "geçersiz";
Console.WriteLine($"Tarih | {dateText} | {result}");
}
static void ShowNumber(string input, string cultureName, CultureInfo culture)
{
bool valid = decimal.TryParse(
input,
NumberStyles.AllowDecimalPoint,
culture,
out decimal value);
string result = valid
? value.ToString(CultureInfo.InvariantCulture)
: "geçersiz";
Console.WriteLine($"{cultureName} | {input} | {result}");
}
Beklenen sayısal sonuçlar şunlardır: tr-TR kültüründe 12,5 değeri 12.5 olarak başarılı biçimde dönüştürülür. Aynı kültürde 12.5 ve abc geçersizdir. InvariantCulture altında ise 12.5 başarılı, 12,5 ve abc başarısız olur. Başarılı sonuçlar InvariantCulture ile yazdırıldığı için ekranda ondalık ayırıcı nokta görünür.
Tarih bölümünde yalnızca yyyy-MM-dd biçimi kabul edilir. 2024-09-24 başarılı olurken 24.09.2024 geçersiz kabul edilir. Böylece tarih metninin yalnızca geçerli olması değil, beklenen biçime uyması da denetlenir.
Parse, TryParse ve kültür seçimi ne zaman kullanılmalı?
Yöntem seçimini girdinin kaynağına ve biçim sözleşmesine göre yapmalısın. Kullanıcı tarafından yazılan metinlerde başarısızlığı kontrol edebilmek için TryParse ailesi daha uygun bir başlangıçtır.
| Durum | Yöntem veya ayar | Neden |
|---|---|---|
| Biçimi sözleşmeyle belirlenmiş veri | Parse |
Biçim önceden güvenilir biçimde belirlendiyse doğrudan değer üretir; uyumsuzluk istisna olarak görünür. |
| Kullanıcı girdisi | TryParse |
Dönüşüm sonucunu bool ile bildirir ve hatalı metni kontrollü biçimde ele almana yardım eder. |
| Kültüre bağlı sayı | Açık CultureInfo ve uygun NumberStyles |
Ondalık ayırıcının nasıl yorumlanacağını ve binlik ayırıcılara izin verilip verilmeyeceğini belirler. |
| Kesin tarih biçimi | DateTime.TryParseExact, format ve kültür |
Yalnızca tanımladığın tarih şablonuna uyan metinleri kabul eder. |
Parse kullanırken biçim veya değer aralığı sözleşmeye uymuyorsa biçim ya da taşma istisnası oluşabilir. Kültür seçimi de abc gibi geçersiz metinleri veya sayısal aralığı aşan değerleri geçerli hâle getirmez. Bu durumlarda TryParse başarısızlık bildirir.
Girdideki ayırıcıları gelişigüzel biçimde Replace ile değiştirmek yerine, kabul edilen biçimi baştan tanımla. Kesin tarih biçimi ve yöntem parametreleri için Microsoft Learn DateTime.TryParseExact açıklamasına başvurabilirsin.
Özetle, önce beklenen biçimi belirle, ardından uygun kültür ve sayı stilini seçerek kullanıcı girdisini TryParse veya TryParseExact ile doğrula.