C# Yöntemler ve Alanlar - II
Yöntemler ve Alanlar - II Kapsam – Görünürlük – Ömür (Scope – Visibility – Lifetime) Şimdi biraz da değişkenleri inceleyelim.
Bir çok programcı bir yöntemden dönen değeri yöntemin adını çağrıştıracak şekilde isimlendirir. Hipotenus yönteminden dönen değeri dHipotenus isimli değişkende tuttuk, başındaki d de double türünde olduğunu gösterdi. Tabi ki bu bir zorunluluk değildir. Farklı isimler de verilebilir. Hatta Main yöntemindeki Hipotenus yöntemine geçtiğimiz değişkenlerin isimleri Hipotenus yönteminin parametreleri ile aynı olabilir. Çünkü her biri ayrı yöntemler içerisinde tanımlanmışlardır ve görünürlükleri de ait oldukları yöntemle sınırlıdır. .net kütüphanesinde birçok hazır sınıf var ve bu sınıfların birçok yöntemi var. Biz bu yöntemlere argüman geçerken acaba yöntemin içinde bizim gönderdiklerimizle aynı ya da farklı isimlerde değişkenler var mıdır ya da bizim Main içerisinde tanımladığımız değişkenlerle aynı isimde bulunup karışabilecek değişken var mıdır diye hiç düşünmeyiz. Çünkü aynı ya da farklı olması hiçbir karışıklık meydana getirmez.
Yerel değişkenler, yani bir yöntemin içinde tanımlanan değişkenler sadece o yöntemin içinde geçerlidir. Başka bir yöntemin içinden erişilemezler. Örneğin dSonuc değişkenine biz hiçbir zaman Main yöntemi içinden ulaşamayız. Bu duruma yerel değişkenin kapsamı ya da görünürlüğü kendisini içeren yöntemle sınırlıdır deriz. Yöntem aynı zamanda değişkenlerin ömürlerinin ne kadar olacağına da karar verir. Yöntemin çalışması sona erdiğinde, yerel değişkenleri tutan stack bölgesi de serbest bırakılır.
Dikkat ederseniz hipotenüs hesabı yapan programımızda Hipotenus isimli yöntem içinde dSonuc diye bir yerel değişken var. Ama d1 ve d2 için değişken değil de parametre ifadesini kullandık. Parametreler değişken değildirler. Ama yine de kapsamları, görünürlükleri ya da ömürleri yine ait oldukları yöntemle sınırlıdır.
argüman – parametre (argument – parameter) Argüman ve parametre terimlerini biraz daha açıklayıp aralarındaki nüansı belirtmeye çalışalım. Çoğu zaman birbirinin yerine yanlışlıkla kullanılırlar ve zaten çok yakın anlamlıdırlar. Biz bir yönteme argümanlar geçeriz, yöntem de o gelen argümanların değerlerini kendi parametreleri ile eşleştirir ve yöntemin parametreleri bu değerleri alır.
Yerel değişkenler gibi, parametreler de yöntemin içinde görünürlük sahibidir, dışarıdan erişilemez. En önemlisi de parametrelerle argümanlar aynı isimde olmak zorunda değildirler. Yukarıdaki örnekte de zaten ayrı isimler verdik.
Bir yöntemin tanımlanmasında eğer dönen değer için bir tip yazılmışsa, return ifadesi ile bunu mutlaka yapmalıyız. Main yöntemi return ifadesine ihtiyaç duymaz çünkü döndüreceği bir değer yok. Bunu da yöntem tanımlamasında void yazarak belirttik.
Ama yine de dönüş tipi void olan bir yöntemin içinde return kullanmak istersek yöntem gövdesinde en son satıra
return;
yazarak bunu yapabiliriz. Basitçe söylemek gerekirse return ifadesi yöntemin çalışmasını sonlandırır.
Eğer hata ayıklama yapıyorsak, programın bir bölümünde kesmemiz gerekiyorsa aşağıda kalan kısmı yorum cümleleri haline getirebiliriz ya da istediğimiz yere
return;
yazarak Main yöntemini o şekilde çalıştırabiliriz.
Bu durumda derleyici erişilemeyen bir kısım program kodu var anlamına gelen
Unreachable code detected
uyarısını gösterir. Çünkü return ifadesinden sonraki kod çalıştırılmaz.
Bu forumdaki linkleri ve resimleri görebilmek için en az 25 mesajınız olması gerekir.
Çoğu programcı bir yöntemin döndürdüğü değeri yazarken
return (dSonuc);
şeklinde parantezler kullanır ama bunu kullanma zorunluluğu yoktur. Yukarıda yazdığımız programda dSonuc yerel değişkenini devreden çıkarabiliriz.
// -----------------------------------------------------------------
// HipotenusHesaplama2 projesinin kaynak kod dosyası Program.cs
// -----------------------------------------------------------------
using System;
class HipotenusHesaplama2
{
static void Main()
{
Console.Write("Birinci kenarı giriniz: ");
double dKenar1 = Double.Parse(Console.ReadLine());
Console.Write("İkinci kenarı giriniz: ");
double dKenar2 = Double.Parse(Console.ReadLine());
double dHipotenus = Hipotenus(dKenar1, dKenar2);
Console.WriteLine("Hipotenüs uzunluğu " + dHipotenus);
Console.ReadLine();
}
static double Hipotenus(double d1, double d2)
{
return Math.Sqrt(d1 * d1 + d2 * d2);
}
}
Kapsülleme – Genelleme – İzole Etme (Encapsulate – Generalize – Isolate) Program yazarken, bazen yazdığımız bir kod öbeğinin başka zaman da kullanılabileceğini düşünürüz. Bu kod öbeğini bir yöntem içerisine alarak kasülleyebiliriz. Daha sonra bu yöntemi genelleyip bir kapalı kutu içerisinde izole edebiliriz. Bu işi yapmamızın sebebi tekrar kullanılabilir kod yazmak ve tekrar tekrar kod yazmaktansa yazılmış olanı kullanmaktır. Ne kadar az kod yazarsak o kadar az hata yaparız.
Başka bir programda Hipotenus hesabı yapan kod öbeğini kullanmak istersek, onu bir yöntem içerisinde izole ettiğimiz için, yöntemi kopyala yapıştır yaparak kolayca başka programda kullanılır hale getirebiliriz.
Tekrar kullanacağımız kod öbeğini bir yöntemin içerisinde izole edip kapsülledik. Test edip hatasız hale getirdik. İyi bir şekilde dokümantasyonunu yapıp içerisinde yapılan işleri kolayca anlaşılır hale getirdik. Daha sonra böyle bir hesap yapan yöntem lazım olduğunda içerisinde işlerin nasıl halledildiğini önemsemeksizin yöntemimizi kopyala yapıştır yaparak diğer programa taşır ve kullanırız.
Ama daha iyi yaklaşımlar da var. Aşağıda adım adım Hipotenus yönteminin diğer programlarda kullanılabilir olması için yapmamız gereken işlemler var. Öncelikle Hipotenus yöntemi için ayrı bir sınıf oluşturacağız daha sonra da her yöntem için ayrı bir kaynak kod dosyası oluşturacağız.
Bir program aşağıdaki genel yapıda olur.
using System;
class BenimSinif
{
// Main ya da diğer yöntemler
}
Bu konuya kadar yapılan çalışmalarda bir program bir tane sınıftan oluştu. Bu sınıf da sadece Main adlı bir tek yöntemden oluştu.
Bir sınıf birden çok yöntemden oluşabileceği gibi bir C# kod dosyası da birden çok sınıf içerebilir. Ayrıca yeni sınıfın diğer sınıfa göre nerede bulunduğu da önemli değildir.
using System;
//Yeni sınıf buraya gelebilir.
class BenimSinif
{
// Main ya da diğer yöntemler
}
//Yeni sınıf buraya da gelebilir
Eğer bir kod dosyası birden çok sınıf barındırıyorsa, Main yöntemine sahip olan temel sınıfı en üste, diğerlerini de sırasıyla onun altına koymayı tercih ediyorum.
Yeni eklediğimiz sınıfla birlikte kod dosyamız şu hale gelecektir.
ing System;
class BenimSınıf
{
// Main ve diğer yöntemler buraya gelir.
}
class YeniSınıf
{
// Sınıfın içindeki yöntemler
}
Şimdi yukarıda bahsedilen şeyleri birleştirip hipotenüs hesabı yapan programı yeniden yazalım.
// -----------------------------------------------------------------
// HipotenusHesaplama3 projesinin kaynak kod dosyası Program.cs
// -----------------------------------------------------------------
using System;
class HipotenusHesaplama3
{
static void Main()
{
Console.Write("Birinci kenarı giriniz: ");
double dKenar1 = Double.Parse(Console.ReadLine());
Console.Write("İkinci kenarı giriniz: ");
double dKenar2 = Double.Parse(Console.ReadLine());
double dHipotenus = Hesaplamalar.Hipotenus(dKenar1, dKenar2);
Console.WriteLine("Hipotenüs uzunluğu " + dHipotenus);
Console.ReadLine();
}
}
class Hesaplamalar
{
public static double Hipotenus(double d1, double d2)
{
return Math.Sqrt(d1 * d1 + d2 * d2);
}
}
Programın sınıf diyagramı (class diagram) aşağıdaki şekildedir. Diyagram programın anlaşılmasını kolaylaştıracaktır.
Bu forumdaki linkleri ve resimleri görebilmek için en az 25 mesajınız olması gerekir.
Yeni sınıfa Hesaplamalar ismini verdik. İçinde şu anda bir tane yöntem var ama daha sonra gerektikçe başka yöntemler de eklenebilir.
Hipotenus yönteminin diğer sınıf içerisinden de ulaşılabilir olması için başına public anahtar kelimesini ekledik.
public static double Hipotenus(double d1, double d2)
public ve static anahtar kelimelerinin hangisinin diğerinden önce yazıldığı önemli değildir ve bunlara yöntem niteleyicileri (method modifier) denir. Ama yöntemin dönüş tipi olan double muhakkak bu ikisinden sonra yazılmalıdır.
public anahtar kelimesi, erişim niteleyicileri (Access modifier) adı verilen niteleyicilerdendir. Bunlar public, private, protected, internal ve protected internal kelimeleridir. Yeri gelmişken public kelimesinden kısaca bahsedelim ama diğerlerini zaten başka bir yazıda anlatacağız.
Eğer hiç erişim niteleyicisi yazmazsak, varsayılan erişim niteleyicisi private niteleyicisidir, yazmasak da private niteleyicisinin özellikleri geçerli olur. Bu durumda bu niteleyiciye sahip olan yöntem sadece kendisini barındıran sınıfın içinden erişilebilir ama başka bir sınıftan erişilemez. Eğer public niteleyicisi kullanırsak, diğer sınıflar içerisinden de çağrılıp kullanılabilir.
Programımızdaki diğer değişiklik ise Hipotenus yönteminin kullanılmasında oldu. Daha önce kendisini çağıran Main yöntemi aynı sınıfın içinde bulundukları için aşağıdaki şekilde kullanmıştık.
double dHipotenus = Hipotenus(dKenar1, dKenar2);
Ama şimdi farklı sınıfların içinde olduklarından kullanımı aşağıdaki gibi değişti.
double dHipotenus = Hesaplamalar.Hipotenus(dKenar1, dKenar2);
Şimdi diğer static yöntemlerin kullanımına benzedi.
İsim uzayı meselesine de değinelim. .net Framework içerisindeki bütün sınıflar bir isim uzayının içerisinde organize olmuştur. Mesela System isim uzayı çok gerekli olan birçok sınıfı barındırır.
Eğer bir isim uzayı belirtmezsek çalışma esnasında yazdığımız sınıflar geçici bir isim uzayı oluşturularak onun parçası haline gelir. Ama tabiî ki bu sınıfların gerçekte dâhil olduğu bir isim uzayı yoktur.
Visual Studio 2005 ile bir proje oluşturduğumuz zaman, Visual Studio 2005 otomatik olarak proje ismi ile aynı isimde bir isim uzayı kendiliğinden oluşturur. Biz istediğimiz isimle değiştirebiliriz ya da silip isim uzayına dâhil olmayan bir sınıf da yazabiliriz.
Şimdi Hipotenus yöntemini izole etmeye diğer adımla devam edelim. Hesaplamalar sınıfını ayrı bir kod sayfasının içerisine koyalım.
Bir sınıfı kendi dosyasında izole ettiğimiz zaman, bu sınıfa ihtiyacı olan başka programlarda da kullanımı kolaylaşır.
Java programlama dilinde ilginç bir kural var. Her bir sınıf ayrı bir kod dosyasında bulunmak zorundadır ve bu dosyaların isimleri içerisindeki sınıfın ismi ile aynı olmak zorundadır. C#’ta böyle bir zorunluluk yok ama eğer kullanmak isterseniz tabiî ki bu çok güzel bir yoldur.
Şimdi Visual Studio 2005 ile AyriDosyalarlaHesaplama adlı bir Konsol Uygulaması projesi oluşturalım.
Bu forumdaki linkleri ve resimleri görebilmek için en az 25 mesajınız olması gerekir.
Projenin Progam.cs isimli kod sayfası aşağıdaki gibi olsun.
// -----------------------------------------------------------------
// AyriDosyalarlaHesaplama projesinin kaynak kod dosyası Program.cs
// -----------------------------------------------------------------
using System;
class AyriDosyalarlaHesaplama
{
static void Main()
{
Console.Write("İlk kenarı gir: ");
double d1 = Convert.ToDouble(Console.ReadLine());
Console.Write("İkinci kenarı gir: ");
double d2 = Convert.ToDouble(Console.ReadLine());
double dHipotenus = Hesaplamalar.Hipotenus(d1, d2);
Console.WriteLine("Hipotenüs uzunluğu: " + dHipotenus);
Console.ReadLine();
}
}
Bu program daha önce yazdığımız HipotenusHesaplama3 projesinin Main yöntemini içeren HipotenusHesaplama3 isimli sınıfının aynısı. Projeyi bu şekilde derleyemeyiz, çünkü Hesaplamalar isimli sınıfı projeye dâhil etmedik.
Şimdi projemize yeni bir dosya ekleyelim. Solution Explorer (Çözüm Gezgini) penceresinde Proje isminin üzerine sağ tıklayıp oradan Add (Ekle), oradan da New Item (Yeni Öğe) seçelim. Yeni kod dosyasının adını Hesaplamalar.cs olarak belirleyelim ve Add butonuna basalım.
Bu forumdaki linkleri ve resimleri görebilmek için en az 25 mesajınız olması gerekir.
Daha sonra aşağıdaki kodu içine ekleyelim.
// ---------------------------------------------------------------------
// AyriDosyalarlaHesaplama projesinin kaynak kod dosyası Hesaplamalar.cs
// ---------------------------------------------------------------------
using System;
class Hesaplamalar
{
public static double Hipotenus(double dKenar1, double dKenar2)
{
return Math.Sqrt(dKenar1 * dKenar1 + dKenar2 * dKenar2);
}
}
Her iki kod dosyasına da using System direktifini ekledik, çünkü ayrı kod dosyaları oldukarından ve her ikisinde de System isim uzayına ait sınıflar kullandığımızdan her ikisine de eklemek gerekiyor.
Projeye yeni bir kod dosyası eklediğimizde Visual Studio 2005, sık kullanılan isim uzayları için using direktiflerini, projenin adıyla aynı olan isim uzayı tanımlamasını, ve kod dosyası ile aynı isimde bir sınıf tanımlamasını kendiliğinden dahil etti. Biz bunları aynı bırakabildiğimiz gibi, kendi isteğimize göre değiştirebiliriz.
Şimdi projemizi derleyip çalıştırabiliriz.
Bu forumdaki linkleri ve resimleri görebilmek için en az 25 mesajınız olması gerekir.
Şimdi, Hesaplamalar sınıfını kullanan başka bir proje oluşturalım. Projenin Program.cs isimli kod sayfası AyriDosyalarlaHesaplama projesinin Program.cs isimli kod sayfası ile aynı oldu.
// -----------------------------------------------------------------
// BaskaProgram projesinin kaynak kod dosyası Program.cs
// -----------------------------------------------------------------
using System;
class BaskaProgram
{
static void Main()
{
Console.Write("İlk kenarı gir: ");
double d1 = Convert.ToDouble(Console.ReadLine());
Console.Write("İkinci kenarı gir: ");
double d2 = Convert.ToDouble(Console.ReadLine());
double dHipotenus = Hesaplamalar.Hipotenus(d1, d2);
Console.WriteLine("Hipotenüs uzunluğu " + dHipotenus);
}
}
Şimdi projeye Hesaplamalar sınıfını dâhil etmek istiyoruz, ama yeni bir kod sayfası oluşturmak istemiyoruz. Daha önce yazdığımız kod sayfasını kullanmasını istiyoruz. Solution Explorer penceresinde projenin üzerine sağ tıklayın Add -> Existing Item (Varolan Öğe) seçtikten sonra AyriDosyalarlaHesaplama projesinin bulunduğu klasörden Hesaplamalar.cs dosyasını seçiyoruz ama Add (Ekle) butonuna basmadan yanındaki küçük oka basıp Add as Link (Bağ Olarak Ekle) seçeneğini seçiyoruz ve kod dosyamız projeye dâhil oluyor. Ama diğerlerinden farklı olarak dosya simgesinin sol tarafında küçük bir ok beliriyor. Bu simge bağlı öğe olduğunu belirtiyor.
Bu forumdaki linkleri ve resimleri görebilmek için en az 25 mesajınız olması gerekir.
Bu forumdaki linkleri ve resimleri görebilmek için en az 25 mesajınız olması gerekir.
Şimdi Hesaplamalar sınıfını kullanan iki tane programımız oldu. Bu dosya üzerinde bir hatayı düzelttiğimizde ya da yeni yöntemler eklediğimizde sadece 1 tane dosyada değişiklik yapmış oluruz. Ama bu durumda Hesaplamalar sınıfını kullanan bütün projeleri yeniden derlememiz gerekir.
Tabi ki, sadece Add (Ekle) butonuna basmış olsaydık kod sayfasını BaskaProgram projesinin klasörüne taşıyacak ve projeye ekleyecekti. Böyle olunca projedeki diğer kod sayfalarından farkı olmayacak ve projenin kendisine ait bir parçası olacaktı. Bu durumda bir dosyadaki değişiklik diğer projedeki dosyayı etkilemeyecekti.
Aslında başladığımız işlem basamaklarını takip edersek bir adım daha kaldı, Hesaplamalar sınıfını ayrı bir dynamic-link library (Devingen bağlı kütüphane) yani DLL içerisine koymak. Bu durumda Hesaplamalar sınıfımız da .net Framework içerisindeki diğer sınıflar gibi olurdu. DLL içerisine alınmış bir sınıf önceden derlendiği için artık başka bir projeye onun kodunu ekleyemeyiz, yani içindeki kod da başkaları tarafından görülmez. Bu adımdaki işlemlerin nasıl yapılacağını başka bir yazıda inceleyeceğiz.