Giriş: Metotlar — Kodun Çalışan Blokları

Metotlar, belirli bir görevi yerine getirmek üzere tasarlanmış, isimlendirilmiş kod bloklarıdır. Tıpkı diğer dillerdeki fonksiyonlar veya prosedürler gibi, metotlar da bir dizi talimatı bir araya getirir ve bu talimatların programın farklı yerlerinden tekrar tekrar çağrılabilmesini sağlar.

Metotların Faydaları:

Kod Tekrarını Önleme (DRY — Don’t Repeat Yourself): Aynı veya benzer kod parçalarını tekrar tekrar yazmak yerine, bu kodu bir metoda yazar ve ihtiyaç duyduğumuz her yerden çağırırız.
Modülerlik ve Organizasyon: Büyük programları daha küçük, mantıksal ve yönetilebilir metotlara ayırarak kodun okunabilirliğini ve anlaşılırlığını artırırız. Her metot belirli bir işe odaklanır.
Yeniden Kullanılabilirlik: Bir kez yazılan bir metot, projenin farklı bölümlerinde veya hatta farklı projelerde tekrar kullanılabilir.
Soyutlama: Metodu kullanan kişi, metodun ne yaptığını bilir ancak nasıl yaptığı detaylarıyla ilgilenmek zorunda kalmayabilir. Metot, içindeki karmaşıklığı gizler.
Bakım Kolaylığı: Bir görevin mantığında değişiklik yapılması gerektiğinde, sadece ilgili metodu güncellemek yeterlidir. Bu değişiklik, metodu çağıran tüm yerlere otomatik olarak yansır. Hata ayıklama da kolaylaşır.
C#’ta metotlar genellikle sınıfların (classes) veya yapıların (structs) üyeleridir.

Bölüm 1: C#’ta Metot Tanımlama

Bir metot tanımlamak, onun erişilebilirliğini, dönüş türünü, adını, alacağı parametreleri ve gerçekleştireceği işlemleri belirtmeyi içerir.

Temel Sözdizimi:

[erişim_belirleyici] [static] [async] dönüş_türü MetotAdi([parametre_listesi])
{
// Metot Gövdesi: Çalıştırılacak kodlar
// [return dönüş_değeri;] // Eğer dönüş_türü void değilse
}
erişim_belirleyici: Metodun nereden çağrılabileceğini belirler (public, private, protected, internal vb.). Varsayılan (eğer belirtilmezse) genellikle private’dır.
static: Metodun bir statik metot olduğunu belirtir. Statik metotlar, sınıfın bir nesne örneği oluşturulmadan, doğrudan sınıf adı üzerinden çağrılır (Math.Sin(), Console.WriteLine()). Statik metotlar, sınıfın örnek (instance) üyelerine (this kullanarak) doğrudan erişemezler. Eğer static belirtilmezse, metot bir örnek (instance) metodudur ve sınıfın bir nesnesi üzerinden çağrılır (nesne.MetotAdi()). Örnek metotları this anahtar kelimesi ile nesnenin diğer üyelerine erişebilir.
async: Metodun bir asenkron metot olduğunu belirtir. İçinde await anahtar kelimesinin kullanılmasına izin verir ve genellikle Task veya Task döndürür. (Asenkron Programlama konusu).
dönüş_türü (Return Type): Metodun çağrıldığı yere geri döndüreceği verinin türünü belirtir (int, string, bool, void, Ogrenci, List vb.). Eğer metot bir değer döndürmüyorsa, dönüş türü void olur.
MetotAdi: Metoda verilen isimdir (PascalCase adlandırma kuralı önerilir).
parametre_listesi: Metodun dışarıdan alacağı girdileri (verileri) tanımlar. Parantez () içine yazılır. Parametre yoksa parantezler boş kalır (). Birden fazla parametre varsa virgülle ayrılır. Her parametre tür parametreAdi şeklinde tanımlanır.
{ … } (Metot Gövdesi): Metodun çağrıldığında çalıştırılacak olan C# ifadelerini içerir.
return dönüş_değeri;: Eğer metodun dönüş türü void değilse, metot return anahtar kelimesiyle belirtilen dönüş türüyle uyumlu bir değer döndürmek zorundadır. return ifadesi aynı zamanda metodun çalışmasını o noktada sonlandırır. void metotlarda da akışı erken bitirmek için return; kullanılabilir.
Örnek Metot Tanımları:

using System;
using System.Collections.Generic;
public class Hesaplayici
{
// Public, Örnek Metodu, int döndüren, iki int parametre alan
public int Topla(int sayi1, int sayi2)
{
int sonuc = sayi1 + sayi2;
return sonuc;
}
// Public, Örnek Metodu, değer döndürmeyen (void), bir string parametre alan
public void MesajYazdir(string mesaj)
{
if (string.IsNullOrEmpty(mesaj))
{
Console.WriteLine("Mesaj boş olamaz!");
return; // void metotta erken çıkış
}
Console.WriteLine($"Mesaj: {mesaj}");
}
// Private, Örnek Metodu, bool döndüren, parametresiz
private bool DogrulamaYap()
{
// ... karmaşık doğrulama mantığı ...
Console.WriteLine("Doğrulama yapılıyor...");
return true; // Şimdilik hep true dönsün
}
// Public, Statik Metot, double döndüren, bir double parametre alan
public static double KareAl(double sayi)
{
return sayi * sayi;
}
// Public, Örnek Metodu, List döndüren, int parametre alan
public List TekSayilariGetir(int limiteKadar)
{
if (!DogrulamaYap()) // Private metodu çağırabilir
{
return new List(); // Boş liste döndür
}
List tekler = new List();
for (int i = 1; i <= limiteKadar; i += 2)
{
tekler.Add(i);
}
return tekler;
}
}
Bölüm 2: Metot Çağırma (Method Invocation)

Bir metodu çalıştırmak için adını ve (varsa) gereken argümanları parantez içinde belirterek çağırırız.

Örnek Metotlarını Çağırma: Sınıfın bir nesnesi üzerinden nokta (.) operatörü ile çağrılır.
Statik Metotları Çağırma: Doğrudan sınıf adı üzerinden nokta (.) operatörü ile çağrılır.
Örnek:

public class MetotCagirma
{
public static void Main(string[] args)
{
// Örnek metotlarını çağırmak için nesne oluştur
Hesaplayici hesap = new Hesaplayici();
// Örnek metotlarını çağırma
int sonucToplama = hesap.Topla(15, 7); // sonucToplama = 22
Console.WriteLine($"Toplama Sonucu: {sonucToplama}");
hesap.MesajYazdir("C# Metotları");
hesap.MesajYazdir(null); // Mesaj boş olamaz! yazdırır
List tekSayilar = hesap.TekSayilariGetir(10);
Console.WriteLine("Tek Sayılar:");
foreach (int tek in tekSayilar)
{
Console.Write(tek + " "); // 1 3 5 7 9
}
Console.WriteLine();
// Statik metodu çağırma (nesne örneği gerekmez)
double kare = Hesaplayici.KareAl(9.0);
Console.WriteLine($"9'un Karesi: {kare}"); // 81
}
}
Bölüm 3: Parametreler ve Argümanlar

Parametreler (Parameters): Metot tanımında belirtilen, metodun dışarıdan alacağı verileri temsil eden değişkenlerdir (int sayi1, string mesaj).
Argümanlar (Arguments): Metot çağrılırken parametrelere karşılık olarak gönderilen gerçek değerlerdir (15, 7, “C# Metotları”).
Argümanların türleri, metot tanımındaki parametre türleriyle uyumlu olmalıdır (veya örtük olarak dönüştürülebilir olmalıdır).

Bölüm 4: Parametre Geçirme Mekanizmaları — İşin Özü

C#’ta bir metoda argüman geçirildiğinde, argümanın değeri mi yoksa referansı mı kopyalanır? Bu, argümanın veri tipine (Değer veya Referans Tipi) ve kullanılan parametre değiştiricilerine (ref, out, in) bağlıdır.

4.1. Değer Tiplerinin Geçirilmesi (Varsayılan: Değer ile Geçirme — Pass-by-Value)

Bir değer tipi ( int, double, bool, struct, enum) bir metoda argüman olarak geçirildiğinde, değişkenin değerinin bir kopyası oluşturulur ve bu kopya metot içindeki parametreye atanır.
Metot içinde parametre üzerinde yapılan değişiklikler, metodun dışındaki orijinal argüman değişkenini etkilemez. Çünkü metot, verinin kendisiyle değil, kopyasıyla çalışır.
Örnek (Tekrar):

static void DegeriDegistir(int sayiParam)
{
Console.WriteLine($"Metot İçi (Önce): {sayiParam}"); // 5
sayiParam = 100; // Sadece kopyayı değiştirir
Console.WriteLine($"Metot İçi (Sonra): {sayiParam}"); // 100
}
public static void Main(string[] args)
{
int orjinalSayi = 5;
Console.WriteLine($"Metot Öncesi: {orjinalSayi}"); // 5
DegeriDegistir(orjinalSayi); // Değerin kopyası metoda gider
Console.WriteLine($"Metot Sonrası: {orjinalSayi}"); // 5 (Orijinal değişmedi!)
}
4.2. Referans Tiplerinin Geçirilmesi (Varsayılan: Referansın Değeri ile Geçirme — Pass-by-Value-of-Reference)

Bir referans tipi ( string, object, dizi, sınıf örneği) bir metoda argüman olarak geçirildiğinde, değişkenin tuttuğu referansın (bellek adresinin) bir kopyası oluşturulur ve bu kopya metot içindeki parametreye atanır.
Hem metot dışındaki orijinal değişken hem de metot içindeki parametre, Heap’teki aynı nesneyi işaret eder.
Bu nedenle, metot içinde parametre aracılığıyla nesnenin içeriğinde (özelliklerinde) yapılan değişiklikler, metot dışındaki orijinal nesneyi de etkiler.
Ancak, metot içinde parametreye new ile tamamen yeni bir nesne referansı atanırsa, bu atama sadece metot içindeki parametre kopyasını etkiler, metot dışındaki orijinal değişkenin referansını değiştirmez.
Örnek (Tekrar):

public class VeriTutucu { public int Deger; } // Basit referans tipi
static void ReferansiDegistir(VeriTutucu vtParam)
{
Console.WriteLine($"Metot İçi (Önce): vtParam.Deger = {vtParam.Deger}"); // 10
// Parametre üzerinden orijinal nesnenin içeriğini değiştir
vtParam.Deger = 100;
Console.WriteLine($"Metot İçi (Sonra): vtParam.Deger = {vtParam.Deger}"); // 100
// Parametreye YENİ bir nesne ata (bu dışarıyı etkilemez)
// vtParam = new VeriTutucu { Deger = 999 };
// Console.WriteLine($"Metot İçi (Yeni Atama Sonrası): vtParam.Deger = {vtParam.Deger}"); // 999
}
public static void Main(string[] args)
{
VeriTutucu orjinalVeri = new VeriTutucu { Deger = 10 };
Console.WriteLine($"Metot Öncesi: orjinalVeri.Deger = {orjinalVeri.Deger}"); // 10
// Referansın kopyası metoda gider, ikisi de aynı nesneyi işaret eder
ReferansiDegistir(orjinalVeri);
// Metot içinde nesnenin içeriği değiştiği için orijinal de etkilenir
Console.WriteLine($"Metot Sonrası: orjinalVeri.Deger = {orjinalVeri.Deger}"); // 100 !
}
4.3. Parametre Değiştiricileri: Davranışı Değiştirmek

C#, varsayılan “değer ile geçirme” davranışını değiştirmek için özel anahtar kelimeler sunar: ref, out ve in. Bu değiştiriciler hem metot tanımında hem de metot çağrısında kullanılmalıdır.

A) ref Değiştiricisi (Referans ile Geçirme — Pass-by-Reference)

Amacı: Bir parametrenin referansıyla geçirilmesini sağlar. Bu, hem değer tipleri hem de referans tipleri için geçerlidir.
Davranış:
Metoda değişkenin kendisi (bellekteki yeri) geçirilir, kopyası değil.
Metot içinde parametreye yapılan herhangi bir değişiklik (yeni değer atama dahil), metot dışındaki orijinal argüman değişkenini doğrudan etkiler.
Değer Tipleri İçin: ref kullanmak, değer tipinin kopyalanmasını engeller ve metot içindeki değişikliğin dışarıya yansımasını sağlar.
Referans Tipleri İçin: ref kullanmak, metot içinde parametreye yeni bir nesne referansı atandığında bile bu değişikliğin dışarıdaki orijinal değişkene yansımasını sağlar (varsayılan davranışta bu olmazdı).
Gereklilik: ref ile geçirilecek argümanın metot çağrılmadan önce mutlaka bir başlangıç değeri atanmış olması gerekir. Derleyici bunu kontrol eder.
Örnek:

static void RefIleDegistir(ref int sayiRef, ref Ogrenci ogrRef)
{
Console.WriteLine($"\nMetot İçi (ref Önce): sayi={sayiRef}, ogr Adı={ogrRef.Ad}");
sayiRef = 500; // Orijinal 'disSayi' değişecek!
ogrRef.Ad = "Ref ile Değişti"; // Orijinal 'disOgr' nin içeriği değişecek (bu ref olmadan da olurdu)
// ref sayesinde YENİ NESNE ataması da dışarıyı etkiler!
ogrRef = new Ogrenci("Yeni Ref Öğrenci", 0, "");
Console.WriteLine($"Metot İçi (ref Sonra): sayi={sayiRef}, ogr Adı={ogrRef.Ad}");
}
public static void Main(string[] args)
{
int disSayi = 10;
Ogrenci disOgr = new Ogrenci("Eski Öğrenci", 21, "Kimya");
Console.WriteLine($"Metot Öncesi (ref): disSayi={disSayi}, disOgr Adı={disOgr.Ad}");
// Metodu çağırırken de 'ref' kullanmak zorunlu!
RefIleDegistir(ref disSayi, ref disOgr);
Console.WriteLine($"Metot Sonrası (ref): disSayi={disSayi}, disOgr Adı={disOgr.Ad}");
// Çıktı: Metot Sonrası (ref): disSayi=500, disOgr Adı=Yeni Ref Öğrenci
}
B) out Değiştiricisi (Çıkış Parametresi)

Amacı: Bir metodun birden fazla değer döndürmesini sağlamanın bir yoludur. Parametrenin metot içinde bir değer alacağını ve bu değerin metot dışındaki orijinal değişkene atanacağını belirtir.
Davranış:
ref’e benzer şekilde referans ile çalışır, metot içindeki atama dışarıyı etkiler.
Temel Farklar:
out parametresi olarak geçirilecek argümana metot çağrılmadan önce bir değer atanmış olması gerekmez.
Metot, out parametresine normal bir şekilde geri dönmeden önce mutlaka bir değer atamak zorundadır. Derleyici bunu kontrol eder. Metot içindeki önceki değeri okunamaz.
Kullanım: Genellikle bir işlem yapıp hem işlemin başarılı olup olmadığını (örn. bool dönüş değeri ile) hem de başarılıysa sonucunu ( out parametresi ile) döndürmek için kullanılır (TryParse metotları klasik örnektir).
Örnek:

// Bir string'i sayıya çevirmeyi deneyen ve sonucu out ile veren metot
static bool SayiyaCevir(string girdi, out int sonuc)
{
// 'sonuc' parametresine metot bitmeden değer atamak zorundayız.
// Başlangıçta genellikle varsayılan değer atanır.
sonuc = 0;
try
{
sonuc = int.Parse(girdi);
return true; // Başarılı
}
catch (FormatException)
{
return false; // Başarısız
}
catch (OverflowException)
{
return false; // Başarısız (Taşma)
}
// finally { } // finally olsa bile öncesinde 'sonuc'a atanmalı
}
public static void Main(string[] args)
{
string kullaniciGirdisi = "12345";
int cevrilenSayi; // Başlangıç değeri atanması gerekmez!
// Metodu çağırırken de 'out' kullanmak zorunlu!
if (SayiyaCevir(kullaniciGirdisi, out cevrilenSayi))
{
Console.WriteLine($"Çevirme başarılı: {cevrilenSayi}"); // 12345
}
else
{
Console.WriteLine("Geçersiz sayı formatı.");
}
string gecersizGirdi = "abc";
int gecersizSonuc;
if (SayiyaCevir(gecersizGirdi, out gecersizSonuc))
{
Console.WriteLine($"Çevirme başarılı: {gecersizSonuc}");
}
else
{
Console.WriteLine($"Geçersiz girdi, sonuç: {gecersizSonuc}"); // Geçersiz girdi, sonuç: 0 (metot içindeki ilk atama)
}
}
C) in Değiştiricisi (Salt Okunur Referans — C# 7.2+)

Amacı: Özellikle büyük struct’lar (değer tipleri) için performansı optimize etmek amacıyla kullanılır. Normalde büyük struct’lar metoda değer ile geçirildiğinde tamamı kopyalanır, bu maliyetli olabilir. in değiştiricisi, struct’ın referansıyla geçirilmesini sağlar (kopyalama maliyetini önler), ancak metot içinde bu parametrenin değerinin değiştirilemeyeceğini garanti eder (salt okunurdur).
Davranış:
Argüman referans ile geçirilir (kopyalama yok).
Metot içinde in parametresine yeni bir değer atanamaz veya üyeleri (eğer struct mutable ise) değiştirilemez. Derleyici bunu zorlar.
Argümanın metot çağrılmadan önce başlatılmış olması gerekir.
Kullanım: Büyük boyutlu struct’ları performansı etkilemeden metotlara geçirmek ve metodun bu struct’ı değiştirmeyeceğinden emin olmak için kullanılır. Referans tipleri için pek anlamlı değildir (zaten referansla geçerler ve in onların içeriğinin değiştirilmesini engellemez, sadece referansın yeniden atanmasını engeller).
Örnek:

struct BuyukVeri // 16 byte'tan büyük bir struct varsayalım
{
public long Veri1, Veri2, Veri3, Veri4;
// ... belki daha fazla alan ...
// Metot bu struct'ı değiştiremez
public void Goster(in BuyukVeri baskaVeri)
{
Console.WriteLine($"Gosterilen Veri1: {baskaVeri.Veri1}");
// baskaVeri.Veri1 = 99; // Hata! 'in' parametresi değiştirilemez.
// baskaVeri = new BuyukVeri(); // Hata! 'in' parametresine atama yapılamaz.
}
}
public static void Main(string[] args)
{
BuyukVeri veri1 = new BuyukVeri { Veri1 = 10, Veri2 = 20, Veri3 = 30, Veri4 = 40 };
BuyukVeri veri2 = new BuyukVeri { Veri1 = 5 };
Console.WriteLine($"Metot Öncesi veri1.Veri1: {veri1.Veri1}");
// 'in' ile çağırmak opsiyoneldir ama okunabilirlik için iyi olabilir
veri1.Goster(in veri2);
// Veya sadece
// veri1.Goster(veri2); // Derleyici yine de referansla geçebilir (optimizasyon)
Console.WriteLine($"Metot Sonrası veri1.Veri1: {veri1.Veri1}"); // Değişmedi (zaten değiştirilemezdi)
}
Özet Tablo (Parametre Değiştiriciler):

DeğiştiriciArgüman Başlatma Gerekli mi?Metot İçinde Değiştirilebilir mi?Metot İçinde Atama Zorunlu mu?Geçirme ŞekliAmaç(Yok)EvetEvet (Kopya veya İçerik)HayırDeğerle / Ref. DeğeriyleVeri geçirme (orijinali koru — değer tipi, veya içeriği değiştir — ref tipi)refEvetEvet (Orijinali etkiler)HayırReferanslaMetodun orijinal argümanı değiştirmesini sağlamakoutHayırEvet (Orijinali etkiler)EvetReferanslaMetottan birden fazla değer döndürmekinEvetHayırHayırReferansla (Readonly)Büyük struct’ları kopyalamadan geçirmek (performans), değiştirilemezlik

Bölüm 7: Diğer Parametre Türleri

Opsiyonel Parametreler: Metot tanımında parametreye varsayılan bir değer atanarak, metot çağrılırken o argümanın gönderilmesi isteğe bağlı hale getirilir. Varsayılan değerli parametreler, parametre listesinin sonunda yer almalıdır.
void MesajGonder(string mesaj, string alici = "Herkes", int oncelik = 1) { Console.WriteLine($"Kime: {alici}, Öncelik: {oncelik}, Mesaj: {mesaj}"); } MesajGonder("Toplantı var"); // Kime: Herkes, Öncelik: 1, Mesaj: Toplantı var MesajGonder("Acil!", "Yönetim"); // Kime: Yönetim, Öncelik: 1, Mesaj: Acil! MesajGonder("Güncelleme", oncelik: 5); // İsimlendirilmiş argümanla sadece önceliği değiştir
İsimlendirilmiş Argümanlar (Named Arguments): Metot çağrılırken argümanların sırasını takip etmek yerine, parametreAdi: deger şeklinde isimlerini belirterek argümanları geçmeyi sağlar. Özellikle çok sayıda veya opsiyonel parametresi olan metotlarda okunabilirliği artırır.
MesajGonder(mesaj: "İzin Talebi", oncelik: 10, alici: "İK");
params Anahtar Kelimesi: Bir metodun belirli bir türden belirsiz sayıda argüman almasını sağlar. params ile işaretlenen parametre, metot içinde o türden bir dizi olarak ele alınır. Bir metotta yalnızca bir tane params parametresi olabilir ve her zaman en sonda yer almalıdır.
// Belirsiz sayıda int toplayan metot static int HepsiniTopla(params int[] sayilar) { int toplam = 0; if (sayilar != null) // params dizi null olabilir (çağrıya göre) { foreach (int sayi in sayilar) { toplam += sayi; } } return toplam; } Console.WriteLine(HepsiniTopla(1, 2, 3)); // 6 Console.WriteLine(HepsiniTopla(10, 20, 30, 40, 50)); // 150 Console.WriteLine(HepsiniTopla()); // 0 int[] diziArg = { 5, 5, 5 }; Console.WriteLine(HepsiniTopla(diziArg)); // 15 (Dizi de geçilebilir)
Bölüm 8: Sonuç — Metotlar ve Etkileşim Sanatı

Metotlar, C# kodunun temel yapı ve eylem birimleridir. Kodu organize etmenin, tekrarı önlemenin ve karmaşıklığı yönetmenin anahtarıdırlar. Bir metodun nasıl tanımlandığı (public, static, void, int, parametreler) ve nasıl çağrıldığı temel bilgilerdir.

Ancak metotların gerçek gücü ve bazen karmaşıklığı, onlara veri aktarma şekillerinde yatar. C#’ın Değer Tipleri ve Referans Tipleri arasındaki temel fark, parametrelerin varsayılan olarak nasıl geçtiğini belirler: Değer tipleri kopyalanır (pass-by-value), referans tiplerinin ise referansları kopyalanır (aynı nesneyi işaret ederler).

ref, out ve in anahtar kelimeleri, bu varsayılan davranışı değiştirerek metotlara daha fazla kontrol ve esneklik kazandırır. ref orijinal değişkenin değiştirilmesini sağlarken, out metottan birden fazla değer döndürmeyi mümkün kılar ve in ise büyük değer tiplerini kopyalamadan güvenli bir şekilde geçirmeyi sağlar. Opsiyonel parametreler, isimlendirilmiş argümanlar ve params ise metotların kullanımını daha esnek ve okunabilir hale getirir.

Bu metot tanımlama ve parametre geçirme mekanizmalarına hakim olmak, C#’ta doğru çalışan, verimli, okunabilir ve bakımı kolay kodlar yazmak için vazgeçilmezdir. Bu kavramlar, dilin daha ileri konularını anlamak için sağlam bir temel oluşturur.

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