Makale Özeti

Instance ve Shared Methodları

Makale

CONSTRUCTORS VE DESTRUCTORS 2

 

CONSTRUCTORS VE DESTRUCTORS 2 

 

Instance ve Shared Methodları

Bazı sınıf yapıları içinde sınıfın yeni bir kopyası (instance) alınmadan komutlar işlenebilir. Örneğin; Date bir sınıfdır. Biz bu sınıf altındaki Today methodunu bir instance olmadan çağırabiliriz:

 

MsgBox(Date.Today)

 

Fakat Date sınıfının başka bir elemanı olanı olan Month özelliğini yukarıdaki gibi direk çağıramayız. Önce Date sınıfının bir instance’ını oluşturmamız gerekir.

 

Dim bugun As Date = Now()

MsgBox(bugun.Month)

 

Yeni bir instance oluşturmadan direk sınıf altından çağırdığımız methodlara Shared Methodlar (Date.Today); Classın instance’ına gerek duyduğumuz methodlara ise Instance Methodlar diyoruz(Month). Default olarak bütün methodlar instance methoddur. Bir shared method oluşturmak için Shared keyi kullanmalıyız.

Aşağıdaki örnekle instance ve shared methodları arasındaki ayrım daha iyi anlaşılacaktır;

Önce bir sınıf oluşturalım;

 

Class Class1

    instance field

    Public insfld As Integer

    shared fields

    Public Shared shrfld As Integer

End Class

 

Sonra formumuza aşağıdaki kodu yazalım;

 

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As _ System.EventArgs) Handles MyBase.Load

    Dim a1 As New Class1

    Dim a2 As New Class1

    a1.insfld = 10

    a2.insfld = 20

    MsgBox("a1=" & a1.insfld & " a2=" & a2.insfld)

    a1.shrfld = 10 Class1.shrfld = 10

    a2.shrfld = 20 Class1.shrfld = 20

    MsgBox("a1=" & a1.shrfld & " a2=" & a2.shrfld)

End Sub

 

Program çıktısında arka arkaya iki msgbox kutusu çıkacaktır.

 

a1=10 a2=20 1. çıktı

a1=20 a2=20 2. çıktı

 

Yukarıda da anlattığımız gibi shared methodunda farklı değişkenler de kullanılsa sınıf içinde var olan sadece bir değişken olduğu için sınıf içindeki değişkenin değeri devamlı değişebiliyor. Çünkü bir kopyası (instance) oluşturulmuyor.

 

Shared Methodlu nesneleri Public veya Private olarak tanımlayabiliriz.Aşağıda verilen örnekte aynı kodun hem Public hem de Private kullanımı sonucu farkını göreceğiz:

 

Class hesap

    Public Shared birimfiyat As Integer

    Public ad As String, miktar As Integer

    Sub New(ByVal uad As String, ByVal umiktar As Integer)

        ad = uad

        miktar = umiktar

    End Sub

    Public Function hesap() As Integer

        Return miktar * birimfiyat

    End Function

End Class

 

Formumuza 4 adet textbox koyalım ve içini aşağıdaki şekilde dolduralım;

 

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As _ System.EventArgs) Handles MyBase.Load

    hesap.birimfiyat = 5000

    Dim h As New hesap("elma", 10)

    TextBox1.Text = h.ad     Ürünün Adı

    TextBox2.Text = h.birimfiyat  Ürünün Bir Tanesinin Fiyatı

    TextBox3.Text = h.miktar Ürünün Miktarı

    TextBox4.Enabled = False       

    TextBox4.Text = h.hesap  Hesap Function’ının sonucu

End Sub

 

Yukarıdaki örneği Private olarak tanımlarsak;

 

Class hesap

    Private Shared birimfiyat As Integer

    Public ad As String, miktar As Integer

    Shared Property birim()

        Get

            Return birimfiyat

        End Get

        Set(ByVal Value)

            birimfiyat = Value

        End Set

    End Property

    Sub New(ByVal uad As String, ByVal umiktar As Integer)

        ad = uad

        miktar = umiktar

    End Sub

    Public Function hesap() As Integer

        Return miktar * birimfiyat

    End Function

End Class

 

Görüldüğü gibi Private olarak tanımladığımız için dışarıdan direk bir bağlantı sağlayamıyoruz. Bunun için bir Property yazıyoruz. Bunu da Form içinde aşağıdaki gibi kullanıyoruz;

 

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As _ System.EventArgs) Handles MyBase.Load

    hesap.birim = 5000

    Dim h As New hesap("elma", 10)

    TextBox3.Text = h.ad

    TextBox4.Text = h.birim

    TextBox5.Text = h.miktar

    TextBox6.Text = h.hesap

End Sub

 

Sonuç bir önceki örnekle aynı olacaktır.

 

Destructors

Visual Basic.Net içerisinde nesneler yok edilirken birçok olay meydana gelir. Bu olaylar meydana gelirken kullanılan procedurelere Destructors diyoruz.

 

Visual basic 6.0 daki Class_Terminate event’ı yerine Visual Basic.Net içerisinde Sub Finalize Destructors kullanılmaktadır. Sub Finalize bloğu içerisindeki kodlar nesne(class) kaldırılmadan önce yapılacak işlemleri yürütür. Örneğin program kapanırken veri tabanı ile bağlantıyı kesmek veya değişiklik yapılan bilgileri saklamak amacıyla kullanılabilir.

 

Protected Overrides Sub Finalize()

        Gerekli kodlar

End Sub

 

Genel özellikleri aşağıdaki gibidir;

·         Finalize Destructor bir protected methoddur. Yani sadece bulunduğu sınıf içerisinden veya türetilen sınıfdan çağrılabilir.

·         Finalize Destructors hiçbir parametre almaz.

·         System, sınıf kaldırılırken Finalize methodunu otomatik olarak çağrırır. Bizim elle bir işlem yapmamıza gerek yoktur.

·         Visual basic 6.0 da Class_Terminate olayı, nesne hiçbir değişken tarafından kullanılmadığı veya classların Nothing keyi set edilip referansları silindiği zaman çalışırdı. Bu etkili bir yöntemdi. Fakat ilişkili referanslar varsa bunlar destroy edilmeden kalırlardı. VB.NET te ise, bir nesnenin Nothing keyi set edilirse değişkenler artık tutulmaz. Fakat obje Garbage Collection(Çöp Toplama) başlayana kadar yok edilmez.

 

Overriding; kısaca sınıf için yazılan özel kodlar anlamına gelir. Elimizdeki sınıf bir derived Class ise Base Class içinde de bir Sub Finalize bloğu olacağından bu bloğun derived sınıf ait olduğunu Overrides keyi kullanarak programa anlatabiliriz.

 

Garbage Collection

.Net Framework’ ün bir elemanıdır. Otomatik memory yönetimini gerçekleştirir. Nothing keyi kullanıldığında veya nesne hiçbir değişken tarafından tutulmadığında enable durumuna geçer ve nesnenin kaldırılması için gerekli işlemleri yapar. Objeyi referanslardan sildiğinden, memory için önemli bir rahatlama özelliğidir. Devreye girdiğinde, Finalize methodunu çalıştırır. Garbage Collection arka planda çalışır. Bu işlemler için biz bir kod yazmayız.

Garbage Collection; objenin kaldırıldığı zaman ile collectorün objeyi destroy edip memoryi rahatlatması arasında bir bekleme zamanı meydana getirir. Bazen bu zaman önemli olabilir.

Bu zamanı bertaraf etmek için Garbage Collection system sınıfının Collect methodunu kullanarak kullanılmayan objelere bir güç uygulayabiliriz.

 

GC.Collect()

 

Fakat; Collect methodunu kullanmak çok fazla önerilen bir yöntem değildir. Çünkü Garbage Collection’ a güç uygulanırsa gerekli olmayan diğer nesnelerin de toplanması yüzünden bir düşük performans sorunu olabilir. Bu yüzden Collect methodunu bir garbage yaratıldığına emin olarak ve  çok dikkat ederek  kullanmak gerekir.

 

Dispose Methodu

Finalization ile belli bir bekleme süresi yaratıldığı için bir standart method yaratmak isteyebiliriz. sınıflar içinde kullanılan bu methoda Dispose diyoruz.Common Language Runtime(CLR) tüm kaynakları yönetemez(Örneğin Database connection’ ları). Garbage Collection .Net Framework’ e ait olduğundan Common Language Runtime’ in gösterdiği kaynakları tanır.(managed resources) Bu kaynaklar dışındaki kaynaklar (unmanaged resources) hafızadan kaldırılamayabilir.  Bu yüzden birçok Visual Basic.Net objesi bu kaynakları temizlemek için Dispose yöntemini kullanır.

 

Class kodu içerisinde yazılacak Procedureler

Public Sub Dispose()

        Dispose yaparken kullanılacak gerekli kodlar

End Sub

 

Protected Overrides Sub Finalize()

    ...

    kod içinde Dispose methodunu çağırmak için böyle bir kod olabilir.

    Dispose()

    ...

End Sub

 

Client kod içindeki kodlar

Dim m As New Musteri

    ...

    ...

m.Dispose()

 

Dispose methodunu kullanmak için, yukarıda görüldüğü gibi, sınıf kod içerisine Dispose Sub’ ı yazarız. Ayrıca bu dispose Sub’ ını  Finalize içinden de çağrabiliriz. Programcı Client kod içerisine direk objenin dispose methodunu yazarak dispose kullanılabilir. Eğer dispose methodunu çağırmazsak (yani yukarıdaki örnekteki m.Dispose() yazılmazsa) Garbage Collection meydana gelir ve Finalize Method Dispose methodunu çağırır. Dispose methodu kullanıldığında garbage collection Finalize Methodunu execute yapmaya gerek duymaz.

 

Bunun için Garbage Collection nesnesinin SuppressFinalize (GC.SuppressFinalize) methodunu kullanarak bunu Disable edebiliriz. İllaki Finalize methodu execute yapılmak isteniyorsa GC.Collect() kullanılır.

 

IDisposable Interface

.Net Framework tarafından sağlanan bir arayüz (interface) olan IDisposable, doğru ve kararlı objeler geliştirmek için sunulmuştur. Yönetilemeyen kaynakları temizlemek için etkili bir methoddur.

IDisposable.Dispose’ u  implement ederek, o objenin instance’ ları için scarce kaynaklarının rezerve edilmiş olduğunu söylemiş oluruz. Obje dispose edilince scarce kaynaklarda serbest bırakılır.

Objeler; bu methodu kullanmaya başladıkları (implementing) zaman, tutulan tüm kaynakların serbest bırakılmış olduklarından emin olmalıdırlar. Örneğin; A objesi B objesini ve B objesi de bir C objesini rezerve ettiyse, A’nın Dispose implementation’ ı B deki Disposu ve B üzerindeki Dispose imlementation ise C deki Disposu çağırmalıdır.

Eğer Base Class  IDisposable kullanırsa, Objeler onların Base Classlarındaki Dispose Methodunu çağırmalıdırlar.

 Bu interface, sadece, hiçbir argüman (parametre) almayan Dispose methoduyla kullanılır. Bu arayüzü sınıfa implement ederek, Client koddan kolaylıkla çağrılan  standart bir Dispose methodu elde edebiliriz.

 

Aşağıda konu ile ilgili detaylı bir örnek dizayn var. Örneği incelerseniz açıklamalarda konu ile ilgili açıklayıcı bilgileri bulacaksınız. (Örnek MSDN den alınmıştır)

 

 

 

Imports System

Imports System.ComponentModel

 

Base Class için bir örnek dizayn

Public Class BaseResource

    IDisposable Classa ekleniyor

    Implements IDisposable

    IntPtr - Harici yönetilemeyen kaynak

    Private handle As IntPtr

    Component - Yönetilen kaynak

    Private Components As Component

    Dispose’un çağrılıp çağrılmadığını kontrol eder

    Private disposed As Boolean = False

    BaseResource Object için Constructor

    Public Sub New()

        Constructor için gerekli kodlar.

    End Sub

    IDisposable.Dispose eklenmiş Dispose kodu. Parametre almaz.        

    Bir objeyi dispose ettiğimiz zaman bu kodlar çalışır

    Public Overloads Sub Dispose() Implements IDisposable.Dispose

        Dispose(True)

        Finalization kodunu boşuna çalıştırmamak için kullanılır.

        GC.SuppressFinalize(Me)

    End Sub

    Dispose(disposing As Boolean) iki farklı senaryoyu gerçekleştirir.      

     Eğer disposing = True ise, method direk veya indirek olarak client    

    kod tarafından çağrılır ve yönetilen ve yönetilemeyen kaynaklar

    dispose edilir. disposing = False ise, method çalışma anında yalnızca  

     Finalizer tarafından çağrılarak yalnızca yönetilemeyen kaynaklar      

    dispose edilir.

    Protected Overridable Overloads Sub Dispose(ByVal disposing As Boolean)

        Dispose’ un daha önceden çağrılıp çağrılmadığını kontrol ediyor

        If Not (Me.disposed) Then

                 Eğer disposing = True ise, yönetilen ve yönetilemeyen                

                kaynaklar dispose edilir.

            If (disposing) Then

                Yönetilebilen kaynaklar Dispose edilir.

                Components.Dispose()

            End If

            Yönetilemeyen kaynakları serbest bırakır. disposing = False   
            ise, yalnızca aşağıdaki kodlar çalışır.

            CloseHandle(handle)

            handle = IntPtr.Zero

        End If

        Me.disposed = True

    End Sub

    Finalize method sadece Client kodda Dispose çağrılmadığı zaman

    çalışır.   

    Protected Overrides Sub Finalize()

        Dispose(False)

    End Sub

    Dispose methodu birçok kez çağrılabilir, fakat Dispose edilmiş bir

    nesne tekrar çağrılmışsa bir hata meydana gelecektir.Obje_name

    kısmına objenin ismine string kısmına ise istenmeyen bir hata anında 

    yazılmasını istediğimiz string ifadeleri yazarız

    Public Sub DoSomething()

        If Me.disposed Then

            Throw New ObjectDisposedException(Obje_name,String)

 

        End If

    End Sub

    Yönetilemeyen kaynakları temizlemek için interop kullanırız

    <System.Runtime.InteropServices.DllImport("Kernel32")> _

    Public Shared Function CloseHandle(ByVal handle As IntPtr) As [Boolean]

    End Function

End Class

 

Base Class için bir örnek dizayn.

Bu derived class içinde IDisposable doğal olarak yeralmakta. Çünkü

BaseResource Classa inherits edilmiş.

Public Class MyResourceWrapper

    Inherits BaseResource

    Bir yönetilebilen kaynak

    Private addedManaged As Button

    Bir yönetilemeyen kaynak

    Private addedNative As SqlClient.SqlConnection

    Dispose’un çağrılıp çağrılmadığını kontrol eder

    Private disposed As Boolean = False

    MyResourceWrapper Objesi için Constructor

    Public Sub New()

        MyBase.New()

        Gerekli Constructor kodları

    End Sub

    Protected Overloads Overrides Sub Dispose(ByVal disposing As _

    Boolean)

        If Not (Me.disposed) Then

            Try

                If disposing Then

                    Yönetilebilen kaynaklar Dispose edilir.

                    addedManaged.Dispose()

                End If

                    Yönetilemeyen kaynakları serbest bırakır.

                CloseHandle(addedNative)

                Me.disposed = True

            Finally

                 Call Dispose on your base class.

                MyBase.Dispose(disposing)

            End Try

        End If

    End Sub

End Class

Base Classtan Finalize methodunu ve Parametresiz Dispose methodunu

inheritd ettiği için derived class bunları içermez

 

Bu yazımızda basit ve orta düzeyde, Constructors ve Destructors konuları ve kullanım yolları anlatıldı.