Serdar YILMAZ
Bizimkisi Bir “Bug” Hikayesi...
Serdivan/Sakarya

Arşiv 'not' Kategori

C# – Garbage Collection ve Yıkıcı Metotlar

dotnetYıkıcı metotlara geçmeden önce Garbage Collection mekanizması hakkında bilgi vermekte fayda var.

Garbage Collection

Garbage Collection erişilemeyen nesneleri silerek belleğin verimli bir şekilde kullanılmasını sağlamaktadır. Konuyu örnekler üzerinden açıklamaya devam edelim;

Yukarıdaki kod satırında “new Ogrenci()” komutu ile Heap bellek bölgesinde Ogrenci sınıfından bir nesne oluşturduk. Bu nesneye erişebilmek için adresini, belleğin Stack bölgesinde tutulan “ogr” ismindeki işaretçiye aktardık. Herhangi bir şekilde “ogr” isimli işaretçiyi kaybedersek, Heap bellek bölgesinde oluşturduğumuz nesneye erişmemiz mümkün olmayacaktır. Erişilemeyen nesnelerde Garbage Collection tarafından silinerek bellekte gereksiz yer kaplaması önlenecektir.

Bu örneğimizde Ogrenci sınıfından iki adet nesne oluşturduk. 1. ve 2. satırlarda ilk oluşturduğumuz nesnenin adresini “ogr1” işaretçisine, ikinci oluşturduğumuz nesnenin adresini “ogr2 işaretçisine aktardık. 3. satırda ise ikinci nesnenin adresini, ilk nesnenin adresini tutan “ogr1” işaretçisine aktardık. Yani artık ogr1 işaretçisi, ilk nesnenin adresini değil ikinci nesnenin adresini tutmaktadır. İlk oluşturulan nesnenin adresi kaybedildiği için artık o nesneye ulaşmak mümkün olmayacaktır. Nesneye erişimin mümkün olmadığı durumlarda nesnenin bellekte kalmasının bir anlamı yoktur. Bu yüzden Garbage Collection tarafından silinecektir.

Garbage Collection, Stack, Heap

Garbage Collection mekanizmasının ne zaman devreye gireceği kesin olarak bilinemez. Arkaplanda programcıdan bağımsız bir şekilde çalışmaktadır.

Yıkıcı Metotlar

Erişilemeyen bir nesnenin Garbage Collection tarafından silinmeden hemen önce çalışan metoduna Yıkıcı Metot denilmektedir. Bir nesnenin silinmeden önce yapmasını istediğimiz şeyleri o nesnenin yıkıcı metodu içerisine yazarız.

Yıkıcı Metot Nasıl Tanımlanır ?

  1. Yıkıcı metodun adı sınıf adıyla aynı olmalıdır ve başında “~” işareti olmalıdır.
  2. Parametresi, geri dönüş değeri ve erişim belirteci olmamalıdır.

Oyuncu sınıfından her nesne oluşturulduğunda “OyuncuSayisi” isimli static değişkenin değeri bir arttırılacak ve nesne silinmeden önce değeri bir azaltılacaktır.

Serdar YILMAZ

C# – Byte Birimindeki Sayısal Büyüklüğü Byte’ın Katlarına Çevirme

dotnet

Açıklama

BytesToString() metodu; parametre olarak girilen sayısal büyüklüğü Byte’ın ilgili katına çevirmektedir.

Kod

Önizleme

Serdar YILMAZ

C# – GET ve SET Metotları

dotnet

Set ve Get metotlarını birer kontrol mekanizması olarak düşünebiliriz. Olası problemleri önlemek, işlemleri güvenilir ve kontrollü bir şekilde gerçekleştirmek için Set ve Get metotlarını kullanırız.

Basit bir senaryo üzerinden konumuzu açıklamaya devam edelim. Otel otomasyonu için müşteri bilgilerini tutan bir sınıf tasarladığımızı düşünelim. Müşterinin ad-soyad, TC kimlik numarası ve oda numarası bilgilerini tutmak istiyorsak aşağıdaki gibi bir tasarım yapabiliriz.

Musteri sınıfının üyeleri public olarak bildirildiği için bu üyelere doğrudan erişilip değerler atanabilir. İşte bu noktada kontrolü elimize almamız lazım aksi taktirde TC kimlik numarası eksik/fazla girilebilir veya 120 odalı bir otelde oda numarası negatif veya 120’den büyük girilebilir. Amacımız dikkatsizlik sonucu yaşanabilecek olası sorunların önüne geçmek. Bu yüzden üyelere doğrudan erişimi engelleyip (Private), Get ve Set metotları ile kontrollü bir erişim sağlayacağız.

Sınıfın AdSoyad, TCNo, OdaNo üyelerini diğer sınıfların erişimine kapattık (private) ve bu üyelere olan erişimi adsoyad, tcno, odano özellikleri üzerinden kontrollü bir şekilde sağladık. (else bloklarında exception fırlatabilirdik ancak istisnai durum yönetimini anlatmadığımız için şimdilik es geçiyoruz.)

GET Metodu

Bir özelliğin değeri okunmak istenildiğinde o özelliğe ait GET metodu çalışır.

Console.WriteLine(m1.adsoyad);

m1 nesnesinin içerisindeki adsoyad özelliğinin Get metodu çalışacaktır.

SET Metodu

Bir özelliğe atama yapılmak istenildiğinde o özelliğe ait SET metodu çalışır. Atanan değere SET metodu içerisinde value anahtar sözcüğü ile erişilir. value anahtar sözcüğünün önceden belirlenmiş herhangi bir türü yoktur. Özelliğe atanacak değer hangi türden ise value da o türden olur.

m1.adsoyad=”Serdar Yılmaz”;

m1 nesnesinin içerisindeki adsoyad özelliğinin SET metodu çalışacaktır ve value ifadesi “Serdar Yılmaz” değerini alacaktır.

Bir özelliğin sadece GET metodunu tanımlayarak özelliği sadece okunabilir hale getirebiliriz.

Erişim Belirleyicisi Kullanımı

GET ve SET metotlarında erişim belirleyicilerini kullanarak erişimin sınırlarını belirtebiliriz.

Yukarıdaki örneğimizde SET metodu private olarak bildirildi. Bu yüzden diğer sınıflardan adsoyad özelliğinin değeri okunabilir ancak herhangi bir atama yapılamaz (set metoduna sadece sınıfın içinden erişilebilir). Eğer SET metodunu private olarak bildirmeseydik; adsoyad özelliği public olduğu için SET metodu da otomatikmen public olacaktı.

GET ve SET metotları için herhangi bir erişim belirteci bildirilmezse, varsayılan olarak özelliğin erişim belirtecini alırlar.

Serdar YILMAZ

C# – This Anahtar Sözcüğü

dotnet

this anahtar sözcüğü ilgili nesnenin referansını belirtmektedir. Konuyu daha anlaşılır kılmak için örnek uygulamalar üzerinden gideceğiz.

Yukarıdaki veri modelinde sınıfın üye elemanları ile yapıcı metodun parametrelerinin aynı isimlere sahip olduğu görülmektedir. Peki yapıcı metot içerisinde AdSoyad değişkenine erişmek istediğimizde; sınıfın üye elemanı olan AdSoyad değişkenine mi erişiriz yoksa yapıcı metodun parametresi olan AdSoyad değişkenine mi ? İşte bu noktada this anahtar sözcüğü sorunun cevabını netleştirip, kaynak kodlarımızın okunabilirliğini arttırmaktadır.

this anahtar sözcüğü ile nitelenen değişkenler sınıfın üye elemanlarıdır. Yukarıdaki veri modelinde yapıcı metoda parametre olarak gönderilen değerler, sınıfın üye elemanlarına aktarılacaktır.

Yukarıdaki programımızı inceleyecek olursak; Silindir sınıfının iki adet yapıcı metodu bulunmaktadır. Silindir sınıfından nesne oluşturulurken 3 adet parametre girildiğinde; 1. parametre silindirin yarıçapını, 2. parametre yüksekliğini, 3. parametrede PI sayısının kaç alınacağını belirtecektir.

Eğer Silindir sınıfından nesne oluşturulurken 2 parametre girilirse; 1. parametre silindirin yarıçapını, 2. parametre yüksekliğini belirtecektir ve PI sayısı da “3.1415” olarak alınacaktır. Peki bunu nasıl yaptık ?

İçeriğimizin başında this anahtar sözcüğünün ilgili nesnenin referansını belirttiğini söylemiştik.

public Silindir(double yaricap, double yukseklik) : this(yaricap, yukseklik, 3.1415) { }

this anahtar sözcüğü ile; girilen 2 parametreyle beraber, PI girilmediği taktirde varsayılan olarak kabul edilmesini istediğimiz değerini, double tipinde 3 parametre alan yapıcı metoda gönderdik. Böylece 2 parametre alan yapıcı metodu, 3 parametre alan yapıcı metottan faydalanarak kullandık.

Yapıcı metotların aşırı yüklenmesini anlatırken yukarıdaki programı this anahtar sözcüğünü kullanmadan yazmıştık (Bkz:C# – Yapıcı Metotlar). Kaynak kodlarını karşılaştırıp aradaki farkı daha iyi anlayabilirsiniz.

Yukarıdaki program Opsiyonel(Optional) Parametreler kullanılarak tek bir yapıcı metot ile yazılabilir.

Serdar YILMAZ

C# – Yapıcı Metotlar

dotnet

Bir sınıftan nesne oluşturulduğu an arkaplanda otomatik olarak çalıştırılan metotlara yapıcı metotlar denilmektedir. Bu yüzden nesne oluşturulduğunda otomatik olarak yapılmasını istediğimiz işlemleri yapıcı metotların içerisine yazarız.

Yapıcı Metotlar Nasıl Tanımlanır ? 

  1. Yapıcı metotların isimleri sınıf isimleri ile aynı olmak zorundadır.
  2. Public olarak bildirilmeleri gerekir.
  3. Geri dönüş değerleri yoktur.

new Matematik()” ifadesi ile Matematik sınıfından bir nesne oluşturulduğu an yapıcı metot otomatik olarak çalışacak ve PiSayisi özelliğine 3.1415 değerini, EulerSayisi özelliğine 2.7182 değerini atayacaktır.

Sıradan metotlar gibi yapıcı metotlarda parametre alabilmektedir. Ancak yapıcı metotlar nesne oluşturulduğu an çalıştığı için parametreler nesne oluşturulurken girilmelidir.

Bir önceki yazımızda Sınıfları anlatırken yukarıdaki programı yapıcı metot kullanmadan hazırlamıştık (Bkz:C# – Sınıflar). Her iki kaynak kodu karşılaştırıldığında, yapıcı metodun Main()‘de ki kod kalabalığını azalttığı ve özelliklere olan erişimi daha kontrollü bir şekilde sağladığı görülecektir.

Yapıcı Metotların Aşırı Yüklenmesi

Tıpkı sıradan metotlar gibi yapıcı metotlarda aşırı yüklenebilir. Metotları anlatırken imza kavramına ve metotların aşırı yüklenmesine değinmiştik (Bkz: C# – Metotların Aşırı Yüklenmesi). Yinede kısaca bahsetmek gerekirse; parametre sayısı ve parametrelerin tipinden en az birisinin farklı olması şartıyla birden fazla yapıcı metot tanımlanabilir.

Varsayılan Yapıcı Metot

Her sınıfın biz tanımlasak da tanımlamasak da bir yapıcı metodu vardır. Bu yapıcı metoda varsayılan yapıcı metot denilmektedir. Default olarak sınıf içerisinde yer alan bu yapıcı metodun görevi; sınıf içerisindeki özelliklere(değişkenlere) herhangi bir ilk değer vermediğimizde, bu özelliklerden numerik olanlara “0”, bool tipinde olanlara “false ” ve string gibi referans tipli olanlara da “null” değerini atamaktadır.

Serdar YILMAZ

C# – Sınıflar

dotnet

Sınıflar nesne yönelimli programlamanın en önemli ögesidir. C# %100 nesne yönelimli bir dil olduğu için tüm metot ve özellikler sınıflar içerisinde yer alır. Sınıfları veri yapısı veya veri yapısı modeli olarak tanımlayabiliriz.

Sınıflara Niçin İhtiyaç Duyarız ?

Metotları anlatırken; “Bütün işlemleri tek bir metot içerisinde yapmak yerine alt programlara yani metotlara ayırmak; kod tekrarını azaltır, okunabilirliği arttırır ve programın daha kolay geliştirilebilmesini sağlar. ” demiştik. (Bkz: C# – Metotlar)

Aynı şekilde; program geliştirirken bütün metotları tek bir sınıfın içinde tanımlamak yerine benzer görevleri yerine getiren metotları bir sınıf içerisinde tanımlamak kod tekrarını azaltır, okunabilirliği arttırır ve programın daha kolay geliştirilebilmesini sağlar. Örneğin veritabanı işlemlerini (ekleme, silme, güncelleme, arama…) yapan metotları diğer metotlardan ayırıp farklı bir sınıf içerisinde tanımlamak daha doğru bir yaklaşım olacaktır.

Sınıf Bildirimi ve Üye Elemanlar

Sınıfların üye elemanları özellikler ve metotlardır. Bir sınıf içerisinde çok sayıda özellik ve metot tanımlayabiliriz.

Sınıf ve sınıf üyelerinin bildirimi yukarıdaki şablona uygun bir şekilde yapılmalıdır.

Erişim Belirleyicisi: Metot ve özelliklere olan erişimin sınırlarını belirtmektedir.

  1. Private: Sadece tanımlandığı sınıf içerisinden erişilebilir.
  2. Public: Her yerden erişilebilir.
  3. Internal: Sadece bulunduğu projede erişilebilir.
  4. Protected: Sadece tanımlandığı sınıfta ya da o sınıfı miras alan sınıflardan erişilebilir.

Sınıf Türünden Nesneler Oluşturma

Şimdi, edinmiş olduğumuz bilgileri kullanarak konuya ilişkin bir örnek yapalım ve bu örnek üzerinden sınıfları incelemeye devam edelim.

Ogrenci isminde bir sınıf oluşturduk ve içerisindeki üye elemanları public (Her yerden erişilebilir) olarak bildirdik.

Program sınıfı içerisindeki Main metodunda; “new Ogrenci()” ifadesi ile Ogrenci sınıfından bir nesne oluşturduk. Belleğin heap bölgesinde oluşturulan bu nesneye erişebilmek için adresini, ogr1 adını verdiğimiz referans değişkenine aktardık.

Nesneler belleğin heap bölgesinde, nesnelerin adreslerini tutan referans değişkenleri de stack bölgesinde tutulur.

ogr1 referansı ile nesnenin public üyelerine erişip değerler atadık. Daha son Bilgi() metodunu çağırarak atamış olduğumuz değerleri görüntüledik.

Bir nesne oluşturduğumuz an nesne içindeki üye elemanlara varsayılan değerler atanır. Numarik ise “0”, bool türünde ise “false”, string gibi referans tipliyse “null” değeri atanır.

Programımızın sonraki satırlarında “new Ogrenci()” ifadesi ile yeni bir nesne daha oluşturduk ve adresini ogr2 referans değişkenine aktardık. Benzer şekilde; üye elemanlarına değerler atayıp, Bilgi() metodu ile atamış olduğumuz değerleri görüntüledik.

Ekran Çıktısı: 

Son olarak Sınıflar için kilit nokta sayılabilecek bir kaç hususa değineceğiz.

Örnek programımızda iki adet nesne oluşturduk ve ilkinin adresini ogr1 değişkenine, ikincisinin adresini ogr2 değişkenine atadık. Her iki nesneyi de Ogrenci sınıfından oluşturmamıza rağmen nesneler birbirinden tamamen bağımsızdır. Çünkü içeriğin başında da belirttiğimiz gibi Sınıflar sadece birer veri modelidir. Bir sınıfı model alan çok sayıda nesne oluşturabiliriz ve bu nesneleri birbirinden bağımsız olarak kullanabiliriz.

Bir sınıftan oluşturulan nesnelerin heap bölgesinde, nesnelerin adreslerini tutan referans değişkenlerinin de stack bölgesinde tutulduğunu söylemiştik. Eğer bir sınıftan herhangi bir nesne oluşturulmazsa o sınıf bellekte her hangi bir yer kaplamaz. Özetle sınıf bildirimleri için bellekte yer tahsis edilmez.

Bir sonraki içeriğimiz de yapıcı metotlara, static üyelere ve property‘lere değinerek sınıf tasarımımızı iyileştireceğiz.

Serdar YILMAZ

C# – Opsiyonel ve İsimlendirilmiş Parametreler

dotnet

Opsiyonel(Optional) Parametreler

Parametrelere varsayılan değerler verebilmek için Opsiyonel Parametreleri kullanırız. Varsayılan değeri olan bir parametreye, metot çağrımı esnasında herhangi bir değer verilmediğinde varsayılan değeri metot içerisinde kullanılır.

Opsiyonel parametreler normal parametrelerden sonra yazılmalıdır. Yani Opsiyonel bir parametreden sonra opsiyonel olmayan normal bir parametre yazılamaz.

İsimlendirilmiş(Named) Parametreler

Metot çağrımı yaparken parametre sırasından bağımsız olarak hangi parametreye hangi değeri atayacağımızı açık bir şekilde belirtebiliriz. İsimlendirilmiş parametrelerin kullanımı çok sayıda parametre alan metotların okunabilirliğini arttırmaktadır.

Serdar YILMAZ

C# – Değişken Sayıda Parametre Alan Metotlar

dotnetAşağıda yer alan programı inceleyecek olursak; EnBuyuk() metodu int tipinde 2 adet parametre almaktadır ve sayısal değeri en büyük olanı geri döndürmektedir. EnBuyuk() metoduna çağrıda bulunabilmek için sadece ve sadece 2 adet parametre girmemiz gerekmektedir.

Bir metoda değişken sayıda parametre gönderebilmek için params anahtar sözcüğünü kullanmamız gerekmektedir. Yukarıdaki örnekte yer alan EnBuyuk() metodu sadece 2 adet parametre alabilmekteydi, şimdi bu metodu değişken sayıda parametre alacak şekilde düzenleyelim;

Görüldüğü üzere parametre sayısında herhangi bir kısıt bulunmamaktadır. Metot, iki parametre verilerek de çağrılabilir, dört parametre verilerek de. Çalışma mantığı ise gayet basittir; params anahtar sözcüğü ile dinamik bir dizi oluşturulur ve parametre olarak gönderilen değerler bu diziye eklenir. Metot içerisinde de dizi içerisindeki parametreler kullanılarak istenilen işlemler yapılabilir.

Uygulama

Bu örnekte özellikle dikkatinizi çekmek istediğim nokta; sabit parametreler ile değişken sayıdaki parametrelerin birlikte kullanılabileceği. CiftSayilar() metoduna girilen ilk parametre, sabit bir parametredir. Sayıların yan yana mı, alt alta mı ekrana yazılacağını belirtecektir. İlk parametreden sonra girilen tüm parametreler “sayilar” dizisi içerisinde tutulacaktır.

Metot; “sayilar” dizisi içerisinde bulunan sayılardan çift olanları ekrana yazdırmaktadır.

Serdar YILMAZ

C# – Metotların Aşırı Yüklenmesi

dotnetHer metodun kendine özgü bir imzası bulunmaktadır. İmza;

  1. Metot Adı
  2. Parametre Sayısı
  3. Parametrelerin Tipi

bilgilerini içermektedir. Aynı imzaya sahip birden fazla metot tanımlanamaz. Üç bilgiden en az birinin farklı olması şartıyla metot tanımlanabilir.

Bu bilgilerden yola çıkarak parametre sayısı ve parametrelerin tipinden en az birisinin farklı olması şartıyla aynı ada sahip metotlar tanımlayabileceğimiz sonucunu çıkarabiliriz. Aynı isme sahip farklı metotların tanımlanmasına Metotların Aşırı Yüklenmesi denir.

İmza; metodun geri dönüş değeriyle alakalı bilgi içermez. Sadece ve sadece yukarıdaki 3 bilgiyi içermektedir.

Metot adı ve parametre sayısı aynı olmasına rağmen parametre tipleri farklıdır. Farklı imzalara sahip olacaklarından yukarıdaki gibi bir tanımlama yapılabilir.
Metot adı ve parametrelerin tipi aynı olmasına rağmen parametre sayıları farklıdır. Farklı imzalara sahip olacaklarından yukarıdaki gibi bir tanımlama yapılabilir.
İmza; metodun geri dönüş değeriyle alakalı bilgi içermez. Yukarıdaki metotlar aynı imzaya sahip olduklarından (Metot adı, parametre sayısı ve türü aynı) böyle bir tanımlama yapılamaz.

Hangi Metodun Çağrılacağına Nasıl Karar Verilir ?

Derleyici aynı isme sahip metotlardan hangisini çağıracağına karar vermek için metot bildirimi ile metot çağrımı arasındaki uyuma bakar. Metot çağrımı ile aynı parametre sayısına ve türüne sahip bir metot bildirimi varsa ilgili metot direk çağrılacaktır. Parametre sayısı aynı olmasına rağmen parametre türleri farklıysa veri kaybı olmayacak şekilde uygun bir metot çağrılır. Örneğin double tipinde parametre alan bir metoda int tipinde parametre gönderilebilir.

Uygulama

Serdar YILMAZ

C# – Değer ve Referans Parametreleri

dotnet.Net Platformunda kullanmış olduğumuz veri tipleri Değer tipleri ve Referans tipleri olmak üzere ikiye ayrılmaktadır. Değer Tipleri stack bölgesinde tutulurken, Referans Tipleri heap bölgesinde tutulmaktadır.

Değer Tipleri: “int”, “long”, “float”, “double”, “decimal”, “char”, “bool”, “byte”, “short”, “struct”, “enum”
Referans Tipleri: “string”, “object”, “class”, “interface”, “array”, “delegate”, “pointer”

Değer tipleri veriyi tutan değişken türleridir. Referans türleri ise veri yerine verinin bellekteki adresini tutan değişken türleridir.

Bir metoda parametre olarak Değer Tipli bir değişken verildiğinde; bellekte yeni bir alan oluşturulur ve değişkenin taşıdığı verinin kopyası bu alana yerleştirilir. Metot içerisinde yapılan işlemlerde de yeni oluşturulan bellek bölgesinde bulunan veri kullanılır. Bu yüzden metot içerisinde yapılan değişikliklerden ana değişken herhangi bir şekilde etkilenmez.

Bir metoda parametre olarak Referans Tipli bir değişken verildiğinde; bellekte yeni bir alan oluşturulur ve değişkenin bellekteki adresi bu alana yerleştirilir. Metot içerisinde yapılan işlemlerde yeni oluşturulan bellek bölgesinde bulunan adres kullanılır, bu adreste ana değişkeni gösterdiği için metot içerisinde yapılan değişikler doğrudan ana değişkeni etkileyecektir.

Tüm diziler Referans türlüdür çünkü diziler Array sınıfı türünden bir nesnedir. Bu yüzden dizilerin elemanları parametre olarak kopyalanmaz, kopyalanan sadece dizinin bellekteki adresini gösteren referansıdır.

REF ve OUT İfadeleri

Değer Tipli değişkenlerin adreslerini(referanslarını) parametre olarak aktarabilmek için REF veya OUT ifadelerini kullanmaktayız. Parametre olarak değişkenin adresi gönderildiği taktirde tıpkı referans tipli değişkenlerde olduğu gibi metot içerisinde yapılan değişiklikler ana değişkeni doğrudan etkilenecektir.

Ref ve Out arasındaki tek fark; Out ile tanımlanmış parametrelere ilk değer verme gibi bir zorunluluk yokken ref ile tanımlanmış parametrelere ilk değer mutlaka verilmelidir. Yukarıdaki örnekte “deger” değişkenine ilk değer olarak “0” verilmiştir. Eğer ilk değer ataması yapılmamış olsaydı, ref ifadesini kullanamazdık. Onun yerine out ifadesini kullanmamız gerekirdi.

Serdar YILMAZ