Mlliyet Milliyet Blog Milliyet Blog
 
Facebook Connect
Blog Kategorileri
 

03 Şubat '09

 
Kategori
Yazılım
 

Bir tek kitap okunarak programcı olunur mu? 2

Birkaç gün önce burada kitapyurdu.com’da Memik Yanık’ın yeni C# 3.0 kitabı hakkında yapılan yorumdan yola çıkarak “Bir Tek Kitap Okunarak Programcı Olunur Mu” sorusu bağlamında yazmak istediğim makalenin bir kısmını sizinle paylaşmıştım. Hatta yazmak istediğim makalenin ilk kısmında sizlere 2 soru sormuştum. Aradan geçen 5 günlük sürede bu yazıyı 1000’den fazla okur gördü okudu. Ne ki bugüne kadar sorduğum 2 soruyla ilgili olarak tepki gösteren olmadı. Zaten sorduğum 2 sorunun cevabını Memik Yanık’ın kitabı hariç başka kaynaklarda bulma ihtimali oldukça düşüktü.

Bu makalenin ilk kısmında sorduğum soruyu izninizle tekrar sorayım: “Madem Microsoft’un programcıları her Windows formu için Visual Studio’ya hazırlattıkları kodlarda components adlı bir değişken tanımlamışlar ve neden daha sonra bu değişkeni hiç kullanmamışlar?” Ötesi neden bu değişkenden neredeyse hiç kimse söz etmemiş? Buna rağmen neden Memik Yanık C# 3.0 kitabında components adlı bu değişkenden söz etti? Cevap net: Kolay okunmak ve hemen anlaşılmak. Components adlı değişkenin neden tanımlanıp sonra hiç kullanılmadığından söz edilmezse Dispose işlemini kavramak zorlaşır. Bir çok yerli ve yabancı yazarın önceliği kolay okunmak ve hemen anlaşılmak olmadığı için kitapları Memik Yanık’ın kitaplarından oldukça farklı olmaktadır. İşte size Memik Yanık’ın C# 3.0 kitabından alınma kısa bir metin.

Forma Yerleştirilen Kontroller ve GC

Yukarıdaki sayfalarda yok edici metotlardan ve Garbage Collector’den söz ederken formları özellikle kullandım. Çünkü Show() metodu ile ekrana getirilen formlar kapatıldığında otomatik olarak Dispose edilmektedir. Dolayısıyla programcının hazırlayıp görüntülediği form nesnelerini bellekten silme gibi bir sorunu yoktur. Şimdi de forma yerleştirilip sonradan gereksiz duruma düşmüş veya referansları yok olmuş kontrollerin bellekten silinmesi konusu üzerinde biraz duracağım. Bu amaçla yeni bir proje hazırladım ve projenin ilk formu temsil eden Form1.cs dosyasında aşağıdaki gibi “Edit” adında bir Class hazırladım.

public class Edit : TextBox

{

~Edit()

{

MessageBox.Show("Edit Sınıfının Yok Edici Metodu İşletildi");

}

}

Bu hali ile “Edit” adını verdiğim sınıf yok edici metodu hariç TextBox sınıfından farksızdır. .NET Framework ile gelen TextBox sınıfının mirasçısı bu sınıfı hazırladıktan sonra formun Load olayını temsil eden metodu aşağıdaki gibi düzenleyerek bu sınıfın örneğini aldım.

private void Form1_Load(object sender, EventArgs e)

{

Edit Edit1 = new Edit();

Edit1.Left = 50;

Edit1.Top = 50;

Edit1.Text = "Edit1";

}

Her ne kadar Load olayını temsil eden metotta “Edit” tipindeki nesnenin Left, Top ve Text özelliklerini ayarlamış olsam bile bu şartlarda “Edit1” nesnesi formun üzerinde görüntülenmez. Çünkü bu nesneyi formun Controls koleksiyonuna eklemedim. Bu şartlarda proje çalıştırılıp Edit1 nesnesinin hazırlanması sağlanıp sonra da çalışması sonra erdirilir veya form kapatılırsa “Edit” sınıfının yok edici metodu işletilir. Projenin ilk formunun Load olayını temsil eden metodu aşağıdaki gibi düzenleyip “Edit1” adını verdiğim nesneyi formun Controls koleksiyonuna ekleyip formun üzerinde görüntülenmesini sağlasaydım bu nesne gereksiz nesne durumuna düştüğünde ne olurdu?

private void Form1_Load(object sender, EventArgs e)

{

Edit Edit1 = new Edit();

Edit1.Left = 50;

Edit1.Top = 50;

Edit1.Text = "Edit1";

this.Controls.Add(Edit1);

}

Bu şekilde düzenlenen Form1_Load() metodu sayesinde proje çalıştırıldığında “Edit1” nesnesi formun üzerinde görüntülenir. Daha sonra projenin çalışması sona erdirildiğinde veya form kapatıldığında bu kez “Edit” sınıfının yok edici metodu çalışmaz. Çünkü formun Controls koleksiyonuna eleman olarak eklenen nesneler tıpkı formlar gibi form kapatıldığında otomatik olarak dispose edilmektedir. Başka bir deyişle formların üzerinde görüntüle­nen nesnelerin bellekten temizlenmesi diye bir sorununuz yoktur.

Tahmin edeceğiniz gibi bu bilgiyi başka bir kaynaklarda bulma ihtimaliniz oldukça düşüktür. Çünkü Memik Yanık’ın C# 3.0 kitabında bu metne yer verme nedeni Dispose işleminin kolay anlaşılmasını sağlamaktır. Memik Yanık’ın hemen anlaşılma hem de ilk okumada anlaşılma gibi bir derdi olmasaydı bu 1 sayfalık metni kaleme alıp kitabına koymazdı.

Componets Adlı Değişken Ne İşe Yarar?

Bir önceki yazıda Visual Studio tarafından her Windows formu için hazırlanıp xxx.Designer.cs dosyasına konulan koddaki components adlı değişkenin işlevi hakkında soru sormuştum. Form sınıfının mirasçısı sınıflar için Dispose() metodunun neden ovveride edildiği ile ilgilenmek gibi bir derdiniz yoksa components adlı IContainer tipindeki nesne veya değişkenle zaten ilgilenmezsiniz. Ötesi nasıl olsa formlar ve forma yerleştirilen Control sınıfından türetilmiş nesneler otomatik olarak dispose ediliyor ve bu konu hakkında bilgi sahibi olmama gerek yoktur diyorsanız ilgilenmenize gerek yoktur. Ama madem birçok kaynakta dispose işleminden söz ediliyor işin özünü öğrenmek gerekiyor.

Şimdi gelin bakalım Memik Yanık kitabında bu components nesnesini ve her form için Visual Studio tarafından override edilen Dispose() metodunu nasıl anlatmış birlikte bakalım. Tabii Memik Yanık aleyhtarlığını kendisine misyon edinmiş ve Memik Yanık’ın yazdıklarını okumadan beğenmeme alışkanlığı olanlar burada yazıların ne önemi var diyeceklerdir. Diyebilirler, bu onların hakkıdır. Zaten bizim dediğimiz şu: 1000 sayfalık bir kitabı 2-3 sayfalık konu bağlamında değerlendirmek eksik bir değerlendirme olur. Components adlı nesne ve Dispose() metodunun anlatıldığı sayfaları örnek olsun diye buraya aldım. Yoksa Memik Yanık’ın kitabında olup ta başka kaynaklarda bulamayacağınız bir çok konu vardır. C# 3.0 kitabımdan olduğu gibi aldıklarımı mavi renge boyadım.

Form Sınıfının Dispose Metodu

Visual Studio ile hazırladığınız projeye yeni bir form eklediğinizde bu forma ait Designer.cs dosyasında aşağıdaki gibi bir Dispose() metodu hazırlanmaktadır. Başka bir deyişle Form sınıfı kaynaklı Dispose() metodu override edilmektedir. Aşağıda verilen kodu incelerseniz “Form1” için Visual Studio tarafından override edilen Dispose() metodunun geriye değer göndermediğini ve “disposing” adında bool bir parametreye sahip olduğunu görürsünüz. Metotta ilk olarak “disposing” adlı bool parametrenin true olup olmadığı araştırılmaktadır. disposing adı verilen parametre true ise bu kez IContainer tipindeki components değişkenin null olup olmadığına bakılmaktadır.

partial class Form1

{

private System.ComponentModel.IContainer components = null;

protected override void Dispose(bool disposing)

{

if (disposing && (components != null))

{

components.Dispose();

}

base.Dispose(disposing);

}

}

}

Hem Dispose() metodunun parametresi true hem de IContainer tipindeki değişkenin içeriği null’dan farklı ise Dispose() metodunun parametresiz versiyonu components adlı IContainer tipindeki nesneye uygulanmaktadır. Tam bu noktada bazılarınızın aklına bu components adındaki ve IContainer tipindeki değişkenin işlevi nedir sorusu gelmiş olabilir.

Hatta Visual Studio ile hazırlanan projeleri didik didik etseniz bile bu components adındaki değişkenin hiç kullanılmadığını ve null olarak kaldığını görürsünüz. Bu nedenle birçok kaynakta “components” adlı bu değişkenden hiç söz edilmez. Aslında sizler de bu değişkenle ilgilenmeyebilirsiniz. Madem Microsoft’un programcıları Override ettikleri Dispose() metodu içinde bu değişkenin null olup olmadığını araştırıyorlar biraz üzerinde duralım. Bu amaçla üzerinde çalıştığım projenin ilk formunun Load olayını temsil eden metodu aşağıdaki gibi düzenledim.

private void Form1_Load(object sender, EventArgs e)

{

TextBox Text1 = new TextBox();

Button Dugme1 = new Button();

}

.NET Framework ile gelen 2 sınıfın örneğinin alındığı bu metotta hazırlanıp formun Controls koleksiyonuna eklenmeyen bu 2 nesne Form1_Load() metodunun sonuna gelindi­ğinde her ikisi de gereksiz nesne durumuna düşerler. Bu şartlarda GC uygun gördüğü bir zamanda bu 2 nesneyi bellekten temizler. Bu 2 nesne formun Controls koleksiyonuna eklenseydiler form kapatıldığında ikisi de otomatik olarak dispose edilirdi. Madem bu 2 nesneyi formun Controls koleksiyonuna eklemedik o halde form kapatıldığında bu nesnelerin otomatik olarak dispose edilmesini sağlayacak başka bir teknik olmalıdır.

Bu teknik GC sınıfının Collect() metodunu çağırmak olmadığına göre ve Controls koleksiyonuna eklenmeyen(tabi eklenemeyen nesneler de olabilir) çok sayıda nesne söz konusu ise hepsine tek tek Dispose() metodunu uygulamak mümkündür. Microsoft’un bu konudaki önerisi bütün bu nesneleri(yani Controls koleksiyonuna eklenmeyen nesneleri) bir Container’a eklemek ve hepsini birden formun override edilmiş Dispose() metodu içinde dispose etmektir.

Bu bölümde Container’lar hakkında ayrıntılı bilgi vermesem bile Controls koleksiyonuna eklenmeyen nesnelerin nasıl toptan dispose edildiğini örnekleyeceğim. Madem Form1.Designer.cs dosyasında Container tipinde ve components adında bir değişken tanımlanmış yeni bir değişken tanımlamak yerine formun Load olayını temsil eden metotta Container nesnesi hazırlayıp components adı verilen bu değişkene aktaracağım. Bu amaçla yukarıda verdiğim Form1_Load() metodunu aşağıdaki gibi düzenledim.

private void Form1_Load(object sender, EventArgs e)

{

TextBox Text1 = new TextBox();

Button Dugme1 = new Button();

components = new Container();

components.Add(Text1);

components.Add(Dugme1);

}

Bu andan itibaren bu 2 nesne components adı verilen Container’ın üyesidir. Eğer bu Container nesnesine Dispose() metodu uygulanırsa bütün üyeleri dispose edilmiş olur ki bu işlem formun override edilmiş Dispose() metodunda yapılmaktadır. Aşağıda Form1.Designer.cs dosyasındaki Dispose() metodunu tekrar verdim.

private System.ComponentModel.IContainer components = null;

protected override void Dispose(bool disposing)

{

if (disposing && (components != null))

{

components.Dispose();

}

base.Dispose(disposing);

}

Madem bu formun Load olayını temsil eden metodunda Container nesnesi hazırlanıp components adında ve IContainer tipindeki değişkene aktarıldı, artık if (disposing && (components != null)) karşılaştırması doğru değerini verir. Bu karşılaştırma true iken “components” adlı container nesnesi Dispose() metodu ile dispose edildiğine göre formun Controls koleksiyonuna eklenmeyen nesneler böyle bir yöntemle topluca dispose edilmiş olunuyor.

Bu şekilde formun Override edilmiş Dispose() metodundaki components adlı değişkenin sırrını çözdükten sonra artık Form sınıfı kaynaklı(aslında IComponent arabirimi kaynaklı) Dispose() metodu üzerinde biraz durabiliriz. Bu amaçla daha önce değişik kez bu kitapta kullanılan bir cümleyi buraya tekrar yazacağım: Show() metodu ile ekrana getirilen formlar herhangi bir şekilde kapatıldıklarında Dispose edilmekte yani bellekten silinmektedir. Tabii form kapatılmadan önce FormClosed ve FormClosing olaylarının meydana geldiğini biliyorsunuz. Bu nedenle formun FormClosed ve FormClosing olayları için aşağıdaki gibi 2 metot hazırlayıp sonra da çalışma anında formu ekrana getirip kapatmak isterseniz önce FormClosing olayıyla ilgili metot işletilir. Devamında FormClosed olayını temsil eden metot işletilir.

private void Form1_FormClosing(object sender, FormClosingEventArgs e)

{

MessageBox.Show("Form1'le ilgili FormClosing olayı meydana geldi");

}

private void Form1_FormClosed(object sender, FormClosedEventArgs e)

{

MessageBox.Show("Form1'le ilgili FormClosed olayı meydana geldi");

}

Kapatılmak istenen formla ilgili olarak bu 2 olay meydana geldikten sonra sıra formun Dispose metodunun işletilmesine gelir. Bu 2 olaydan sonra sıranın Dispose() metodunun işletilmesine geldiğini görmek istiyorsanız Form1.Designer.cs dosyasında override edilen Dispose() metodunu aşağıdaki gibi düzenleyebilirsiniz.

protected override void Dispose(bool disposing)

{

System.Windows.Forms.MessageBox.Show("Form1'in Dispose metodu işletildi");

if (disposing && (components != null))

{

components.Dispose();

}

base.Dispose(disposing);

}

Sanırım çalışma anında bir form kapatılmak istendiğinde geri planda meydana gelen olayla­rın ve yapılan işlemlerin sıralaması anlaşıldı. Şimdi gelin Form1.Designer.cs dosyasındaki yani Visual Studio tarafından override edilmiş Dispose() metodunu silelim. Tabi üzerinde çalıştığımız proje deneysel amaçlı ve yukarıda sözü edilen “components” adlı IContainer tipindeki nesneye henüz herhangi bir nesne üye yapılmadığı için Visual Studio tarafından hazırlanan override edilmiş Dispose() metodunu silmek bir soruna neden olmaz. Çünkü form kapatılmak istendiğinde Form sınıfının Dispose() metodunun orijinal hali zaten işletilir. Bu tespitleri yaptıktan sonra Form1.cs dosyasında Form1’in Form sınıfı kaynaklı Dispose() metodunu kendim override ettim. Aslında orijinal haline MessageBox sınıfının Show() metodu ile mesaj veren bir satır eklemekle yetindim.

protected override void Dispose(bool disposing)

{

MessageBox.Show("Form1'in Dispose metodu işletildi");

base.Dispose(disposing);

}

MessageBox.Show() satırı hariç bu hali ile Dispose() metodunu override etmenin herhangi bir işlevi yoktur. Çünkü orijinali ile aynıdır. Şimdi bu metottaki base.Dispose(disposing); satırını silip ondan sonra projeyi çalıştırıp formu kapatmayı bir deneyin. Tahmin edeceğiniz gibi bu satır silindikten sonra formu bilinen yöntemlerle kapatmak mümkün olmaz. Çünkü Windows’tan gelen Kapat mesajını engellemiş oldum. Bu şartlarda forma bir düğme yerleşti­rip Dispose() metodunu aşağıdaki gibi kendiniz işletirseniz formu kapatmış olursunuz.

private void Kapat_Click(object sender, EventArgs e)

{

base.Dispose(true);

}

Tabi bu şartlarda formun FormClosing ve FormClosed olaylarını temsil eden metotlar işletilme şansı bulamazlar. Sanırım konu biraz aydınlandı. Form sınıfının Dispose() metodu hakkında biraz bilgi verdikten sonra şimdi sırada kendi sınıflarımızdan yola çıkarak hazırla­yacağımız nesneleri Dispose() metodu ile nasıl yok edeceğimiz konusu var. Tekrar etmek gerekirse; Show() metodu ile ekrana getirilen ve formların Controls koleksiyonlarına eklenen nesneler otomatik olarak Dispose edildikleri için bunları sorun yapmayabiliriz.

C# kitabımdan olduğu gibi aldığım bu 2 sayfalık metni okudunuz. Tabii bu işi bilen bazı arkadaşlar hemen itiraz edip ne var bunda, bu metinde üzerinde durulacak ne var diye tepki gösterebilirler. Bu arkadaşlara vereceğim cevap şudur: Bu metnin böyle kaleme alınma nedeni kolay okunmaktır, hemen anlaşılmaktır.

Gelelim bu yazının başlığındaki soru üzerinde biraz durmaya. Tabiatıyla yalnızca bir kitap okunarak programcı olunmaz. Ancak okuduğunuz kitap sizi söz konusu programlama diliyle ilgili temel kavramlarla tanıştırıp bu kavramlara sahip olmanızı hedefleyip anlaşılır bir dille bu kavramları size anlatıyorsa programcılık mesleğine iyi bir başlangıç yapmış olursunuz. Yok eğer programcılık öğreneceğim diye kötü kaleme alınmış, zor anlaşılan, yazım hatalarını geçtik neredeyse her sayfasında ayrı bir teknik hata içeren kitap edinip okumaya başlarsanız hevesinizin kaçması ve bu iş bana göre değilmiş deme ihtimaliniz yüksektir.

 
Toplam blog
: 21
: 849
Kayıt tarihi
: 02.08.08
 
 

1992 yılından başlayarak bilgisayar ve programcılık üzerine dergilerinde çok sayıda makale yayınladı..