C# Günlüğüm — Sayı #3

Berkan Şaşmaz
SDTR
Published in
12 min readJul 16, 2019

Merhabalar.

Uzun bir aradan sonra tekrardan sayı #3 ile karşınızdayım. Bu kadar uzun bir ara vermeyi elbette ben de istemezdim fakat bu süreçte hem çok güzel bilgiler edindim hem de iyisiyle kötüsüyle bu zamana kadar deneyimleyemediğim tecrübeleri deneme şansını elde ettim.

Neyse lafı daha fazla uzatmadan, faydalı olması dileği ile buyrun..

Böl ve yönet politikası (Latince: divide et impera deyiminden kaynağını almıştır), rakiplerini bölerek ya da onları bölünmüş vaziyette tutarak zayıf durumda bırakmak isteyen devletlerin izledikleri yoldur.

Bizlerde bilgisayarın anlayabileceği dilde konuşurken optimal çözümü bulmak için bu yöntemi sık sık kullanırız. Öyle ki bir çok kavramın ve algoritmanın altında böl ve fethet stratejisi vardır.

Şimdi sizlere nesne yönelimli programlamanın(object oriented programming) kısaca ne demek olduğundan bahsedeyim. Çözülmesi istenen problemi çeşitli parçalara ayırıp her bir parça arasındaki ilişkiyi gerçeğine uygun bir şekilde belirleme tekniğine nesne yönelimli denir. Bu parçalar arasındaki ilişkiyi kullanıp büyük çaplı programlar geliştirme tekniğine de nesne yönelimli programlama denir. (Nesnelerin kodlarımızdaki karşılığı sınıflardır).

Sınıflar

C# dilinin ve nesne yönelimli programlama tekniğinin en önemli veri yapısıdır. Sınıflar programcıya bir veri modeli sunar. Bu veri modeli kullanılarak çeşitli nesneler oluşturulur.

Not: Sınıfların üye elemanları metotlar ya da özelliklerdir.

Erişim belirleyici(access specifiers): public üye elemanlar genellikle bir sınıfın dışarıya sunduğu arayüzü temsil eder. Ancak bazı durumlarda private olarak tanımlanmış üye elemanları da bu arayüze dahil edilebilir. Bunun için sınıfın içinde özel metotlar tanımlanır. private olarak tanımlanmış üye elemanlara dışarıdan erişmek mümkün değildir. private üye elemanlara ancak tanımlandığı sınıfın içerisindeki üye elemanlar erişebilir. private olarak tanımlanan üye elemanları genellikle sınıfın metotlarını gerçeklerken birtakım ara değerleri tutmak ve işe yarayan metotları kullanabilmek için tanımlanırlar.

Not: Eğer herhangi bir erişim belirleyicisi kullanmamış olsaydık varsayılan olarak private olurdu.

Not: Sınıf bildirimleri için bellekte yer tahsis edilmez. Sınıf bildirimleri sonradan tanımlayacağımız nesneler için derleyiciye nesnenin neye benzeyeceğinin gösterir.

O halde sınıf türünden bir nesnenin bildirimi aşağıdaki şekilde yapılabilir.

KrediHesabi hesap1;

Bu bildirim ile KrediHesabi türünden hesap1 değişkeni bildiriliyor; fakat, henüz bellekte üye elemanları tutmak için yer tahsis edilmedi. Üye elemanlar için bellekte alan tahsisatı yapmak için new anahtar sözcüğü kullanılır. new anahtar sözcüğü ile yeni bir KrediHesabi nesnesinin tanımlanması aşağıdaki gibi yapılır.

KrediHesabi hesap1 = new KrediHesabi();

Sınıflar, için new anahtar sözcüğü ile tanımlandığında sınıfın içindeki bütün üyeler varsayılan değere atanır.

Varsayılan değerler tablosu

Birden Fazla Sınıf Nesnesi Tanımlama

Programımız içinde aynı sınıf türünden birden fazla nesneyi tanımlayabileceğimizi farketmişsinizdir. Ancak tanımladığımız nesneleri birbirlerine atarken dikkat etmemiz gereken birtakım önemli noktalar vardır. Önceki yazılarımda değer ve referans tipleri arasındaki temel farklardan bahsetmiştim. Değer tipleri birbirlerine atanırken bitsel bir kopyalama işleminin olduğunu söylemiştim. Ve atama işleminden sonra her bir nesnenin farklı bellek bölgesindeki verileri temsil ettiğini söyledik. Ancak referans tiplerinin birbirlerine atanması sırasında bu geçerli değildir. Referans türleri değer türlerinden farklı işlem görürler, referans tipi olan iki nesneyi birbirlerine atadığımızda nesnelerin eleman değerleri tek tek kopyalanmaz. Atanan değerler dinamik bellek bölgesindeki nesnelere referans olan adreslerdir. Yani referans türünden iki nesneyi atama operatörü ile eşitlersek iki nesne de aynı bellek bölgesindeki verileri temsil eder, bir nesne üzerinde yaptığımız değişiklik diğer nesneyi de etkiler.

class KrediHesabi
{
public ulong HesapNo;
private double Limit;
public string KartSahibi;
}
class AnaSınıf
{
static void Main(string[] args)
{
KrediHesabi hesap1 = new KrediHesabi();
KrediHesabi hesap2;
hesap1.HesapNo = 999;
Console.WriteLine(hesap1.HesapNo); //Çıktı: 999
hesap2 = hesap1;
Console.WriteLine(hesap2.HesapNo);//Çıktı: 999
hesap2.HesapNo = 222;
Console.WriteLine(hesap1.HesapNo);//Çıktı: 222
}
}

Yukarıdaki programda hesap1 nesnesi için bellekte yer ayrılmasına rağmen hesap2 için bellekte yer ayrılmamıştır. Çünkü new anahtar sözcüğü kullanılmamıştır. hesap2 için sadece stack bellek bölgesinde bir referans tutabilecek kadar alan ayrılmıştır.

hesap2 = hesap1;

ifadesinden sonra hesap2 değişkeninin tuttuğu referans hesap1' in değişkeninin tuttuğu referans ile aynı olmaktadır. Yani her iki değişken de heap alanında aynı bellek bölgesini göstermektedir. Dolayısıyla bu nesnelerin birinde yapılan değişiklik diğerinide etkileyecektir. Nitekim;

hesap2.HesapNo = 222;

deyimi ile sadece hesap2' nin değil aynı zamanda hesap1' in de HesapNo elemanı değiştirilmiştir.

Referans tiplerinin birbirlerine atanması ile ilgili bütün anlatılanların özetini aşağıdaki şemada görebilirsiniz.

Referans tiplerinin birbirlerine atanması

this

Nesneler üzerinden metotlar çağrılırken aslında biz farkına varmadan metotlara gizlice ilgili nesnelerin referansları geçirilir. Örneğin, this anahtar sözcüğünün anlamını daha iyi kavrayabilmek için bir soyutlama yapalım,

Dortgen d1 = new Dortgen();d1.EnBoyBelirle();

yerine aşağıdaki gibi bir kullanım olabilirdi:

Dortgen d1 = new Dortgen();d1.EnBoyBelirle(d1' in referansı);

Eğer this anahtar sözcüğü olmasaydı ikinci şekildeki gibi bir kullanıma mecbur kalacaktık. İkinci şekildeki gibi bir kullanımın kullanışsız olduğunuz söyleyebiliriz. Bu yüzden C# dilini tasarlayanlar d1 nesnesinin referansını gizlice EnBoyBelirle() metoduna aktarmada kullanılacak bir sistem geliştirmişlerdir. İşte this anahtar sözcüğü bu referansı temsil etmektedir.

Not: this anahtar sözcüğünün kullanımına olanak tanımak okunabilirlik açısından önemlidir.

Yapıcı Metotlar(Constructors)

Bu metotlar sayesinde bir nesnenin üye elemanlarına ilk değerler verilir ya da sınıf nesnesi için gerekli kaynak düzenlemeleri yapılır(örneğin dosyalarla ilgili bir sınıf ise dosyaların açılması gibi). Yapıcı metotların geri dönüş değeri yoktur ve yapıcı metotların ismi sınıf ismi ile aynı olmak zorundadır.

Varsayılan Yapıcı Metot(Default Constructors)

Varsayılan yapıcı metot sınıf nesneleri oluşturulduğu anda biz herhangi bir yapıcı metot tanımlamamış olmamıza rağmen otomatik olarak çağrılırlar. Yani her sınıf nesnesinin en az bir yapıcı metodu vardır. Varsayılan bu yapıcının herhangi bir parametresi yoktur. Varsayılan bu metot nesnelerin üye elemanlarına varsayılan değerler(nümerik değişkenler için 0 , referans tipleri için null, bool türü için false) atar. Varsayılan yapıcı metotlar herhangi bir parametre almaz.Bu yüzden hesap1 nesnesi aşağıdaki gibi tanımlanmıştır.

KrediHesabi hesap1 = new KrediHesabi();

Nesneleri bu şekilde tanımlamak zorunda olduğumuz için bütün nesneler için varsayılan yapıcı metot çalıştırılmaktadır. Yapıcı metotları biz kendi sınıflarımız içinden tekrar bildirebiliriz. Bu durumda varsayılan yapıcı metot artık çalıştırılmaz.

Kopyalayıcı Yapıcı Metot(Copy Constructor)

Bir Zaman nesnesini yine bir Zaman nesnesini kullanarak oluşturmak isteyebiliriz. Bu durumda kopyalama yapıcı metotlarını kullanabiliriz. Bu metotların tek bir parametresi vardır. Bu parametreler de sınıf türünden nesnelerdir.

Örneğin bir kopyalama yapıcı metodu aşağıdaki şekilde oluşturulabilir.

class Zaman
{
public int Saat;
public int Dakika;
public int Saniye;

public Zaman(int h,int m,int s)
{
this.Saat = h;
this.Dakika = m;
this.Saniye = s;
}

public Zaman(Zaman yeni) //Kopyalama yapıcı metodu
{
}
}

Bu yapıcı metodu ise aşağıdaki tanımlama ile çağırırız.

Zaman z1 = new Zaman(5,59,68);Zaman z2 = new Zaman(z1);

Yıkıcı Metotlar(Destructors)

C++ dilinde bir sınıfın içinde bir nesne için dinamik olarak alanı tahsis edilmişse nesnenin ömrü dolduğunda bu alanın tekrar geri iade edilmesi gereklidir, zira heap bellek bölgesinden tahsis edilen alanlar geri iade edilmezse bellek sızıntıları(memory leak) olabilir. C++ programcıları bu iade işlemini kendileri yapmaktadır, ancak C# programcılarının bu zahmeti çekmesine gerek yok. Gereksiz Nesne Toplama(Garbage Collection) dediğimiz mekanizma gereksiz nesnelerin tuttuğu referans bölgelerini zamanı ve yeri gelince iade eder. C++’ ta bir nesnenin faaliyet alanı bittiğinde otomatik olarak nesneler yok edilir. Ancak dinamik olarak ayrılmış alanlar yok edilmez. Bu yüzden nesnelerin yok edilmelerinden hemen önce çalışan metotlar yazılır. Bu metotlara yıkıcı metotlar(destructors) denilmektedir.

C#’ ta bu işlemler tamamen farklıdır; gereksiz nesne toplayıcısı(Garbage Collector) bizim yerimize gereksiz alanları iade eder, ancak bu işlemin nesnelerin faaliyet alanlarının bittiği noktada olacağını garanti altına alınmamıştır. Bu yüzden bir nesnenin kapladığı bellek alanlarının ne zaman iade edileceği kesin olarak bilinemez. Fakat C#’ ta bildirilen yıkıcı metotlarının bu iade işleminden hemen önce çalıştırılacağı kesindir.

Yıkıcı metotların isimleri de yapıcı metotlar gibi sınıf ile aynı olmalıdır. İsimlerin başına ~karakteri gelir. Yıkıcı metotların herhangi bir parametresi veya geri dönüş değeri yoktur. Aynı zamanda public ya da private gibi erişim belirteçleri ile işaretlenmezler.

class Dest
{
~Dest()
{
Console.WriteLine("Yikici metot cagrildi");
}
}
class AnaSınıf
{
static void Main()
{
{
Dest d new Dest();
}
Console.WriteLine("Berkan");
}
}

Çıktı:

Berkan
Yikici metot cagrildi

Eğer yukarıdaki program C++ ile yazılmış olsaydı ekran görüntüsü böyle olmazdı. Önce yıkıcı metot çağrılırdı sonra ekrana “Berkan” yazılırdı.

Daha önce ki yazımda belirttiğim gibi d nesnesinin tanımlandığı

{
Dest d new Dest();
}

blogunun sonunda d nesnesine erişmek mümkün değildir. Ancak bloğun dışına gelindiğinde ilk yapılan yıkıcı metodu çağırmak olmamıştır. Önce ekrana “Berkan” yazıldı sonra gereksiz nesne toplama(garbage collection) mekanizması devreye girdi. Tabi nesne bellekten silinmeden önce yıkıcı metodumuzun çağrılacağı garanti olduğu için ekrana “Yikici metot cagrildi” yazılmıştır.

Not: Gereksiz nesne toplayıcısı(garbage collector) bizim istediğimiz dışında çalışmaktadır.

C#’ ta genellikle sınıfın global düzeyde üye değişkenleri ile ilgili işlemler yapmak için kullanılır. Örneğin bir oyun programı düşünün. Oyunun belli bir noktasında oyundaki oyuncu sayısını tutacak bir değişken olsun. Her oyuncu yaratıldığında bu değişken 1 arttırılır, her oyuncunun işlevi bittiğinde ise yıkıcı metot yardımıyla oyuncu sayısı bir azaltılır.

Not: Bir sınıfın sadece bir tane yıkıcı metodu olabilir.

Statik Üye Elemanlar

C# dilindeki bütün metotlara sınıflar üzerinden erişiriz. Çoğu durumda da erişim için bu sınıflardan nesneler oluştururuz. Ancak bazı durumlarda metotları kullanmak için nesne oluşturmamız gereksiz olabilir. Bu durumda statik metotlar, statik üye değişkenler ve statik yapıcı metotlar tanımlanır.

Statik elemanlar bir sınıfın global düzeydeki elemanlarıdır.

Static Metotlar

Not: Sınıflarımızı tasarlarken nesneler ile doğrudan iş yapmayan metotları static olarak bildirmemiz gerekir.

Main() metodunun statik olmasının sebebinin altında bu mantık yatar. Yani amaç Main() metodunun çalışması için herhangi bir sınıf nesnesine ihtiyaç duymadan çalışmasını sağlamaktır.

Not: Bir statik metot içinden sınıfın diğer statik metotları çağrılabilir. Ancak normal üye metot çağrılamaz. Çünkü normal metotlar(statik olmayan) nesneler üzerinde işlem yaparlar. Dolayısıyla nesnelerin adresleri gizlice metoda this referansı ile gönderilir. Ancak statik metotlar sınıfın global metotları olduğu için this referansları yoktur. Bu yüzden statik bir metot içinden normal bir metot çağırmak geçersizdir.

Statik Değişkenler

Statik değişkenler genellikle bir sınıfı global düzeyde ilgilendiren özellikler için kullanılır. Mesela bir oyun programında çalışma zamanının herhangi bir noktasında oyuncu sayısını tutan bir değişken statik olmalıdır.

Not: Her sınıf nesnesi oluşturulduğunda her statik üye değişken için bellekte ayrı yer tahsis edilmez.

Statik Yapıcı Metotlar

Statik yapıcı metotlar bir sınıfın statik değişkenleri ile ilgili işlemler yapmada kullanılır. Bir nesne ilk defa yaratıldığında statik üye değişkenini değiştirmek için genellikle statik yapıcı metotlar tanımlanır.

Not: Statik olan bir metot ile statik olmayan bir değişkeni değiştirmek nasıl mümkün değilse statik olan yapıcılarda statik olmayan değişkenleri değiştiremez.

class Oyuncu 
{
public Oyuncu()
{
Console.WriteLine("Statik olmayan yapici");
}

static Oyuncu()
{
Console.WriteLine("Statik yapici");
}
}
class AnaSınıf
{
static void Main()
{
Oyuncu o = new Oyuncu();
Oyuncu x = new Oyuncu();
}
}

Çıktı:

Statik yapici
Statik olmayan yapici
Statik olmayan yapici

Görüldüğü gibi o nesnesi oluşturulduğunda hem statik yapıcı metot hem de statik olmayan metot çağrılmıştır(önce statik yapıcı metot). Ancak x nesnesi oluşturulduğunda sadece statik olmayan yapıcı metot çağrılmıştır.

Not: Bir nesnenin varlığını kullanarak çağırabileceğimiz tek metot statik yapıcı metottur.

Statik yapıcı metotlar herhangi bir parametre alamazlar. Statik yapıcı metotlar ile genellikle statik değişkenler ile ilgili işlemler yapılır.

Not: Bir nesneyi hangi yapıcı metot ile oluşturursak oluşturalım statik yapıcı metot mutlaka ilk nesne tanımlandığında çalıştırılır.

Statik Sınıflar

Statik sınıflar dile eklenmiş artı bir özellikten ziyade yapmak istemediklerimizi zorlayıcı bir etken olarak sunmak için vardır. Birçok projede bazı sınıfların içindeki bütün üye elemanlar static olarak tanımlanabiliyor. Bu tür durumlara genellikle birbirinden bağımsız bir şekilde iş yapan metotların tanımlandığı sınıflarda karşılaşılmaktadır. Bu durumda o sınıf türünden nesne yaratmak, nesne referansı tanımlama ya da o sınıfı kalıtım yolu ile genişletmek genelde rastlanan birşey değil. Bu yüzden C# dilini tasarlayanlar bu tür durumlarda sınıf ile yapılabilecekleri kısıtlamak(böylece performans sağlamak) ve sadece belirlenen özelliklerde(static) üye elemanların tanımlanabileceği static sınıf kavramını geliştirmişlerdir.

İçinde sadece statik üye elemanları barındıran sınıflar static sınıf olarak tanımlanmalıdır. Bu bir zorunluluk değildir ancak iyi bir kodlama tekniğidir.

Not: const elemanların otomatik olarak static olduğunu unutmayalım.

Not: Static sınıflar içinde static olmayan metot ya da özellik tanımlanamayacağı gibi aynı şekilde static yapıcı metotlar da tanımlanamaz.

Static sınıflar türünden aşağıdaki gibi nesne yaratamayız.

MatematikselIslemler m = new MatematikselIslemler();

Aynı zamanda static sınıf türünden aşağıdaki gibi referanslar tanımlayamayız.

MatematikselIslemler m;

Dolayısıyla bir metodun parametreleri ya da geri dönüş değeri kesinlikle static olan bir sınıf türünden olamaz.

Static sınıflar kod okunabilirliği açısından önemli bir bildirim yöntemidir. Programcı herhangi bir sınıfın static olduğunu gördüğü anda içindeki bütün üye elemanlarının static olduğunu anlayacaktır.

const

Statik üyelerde olduğu gibi sabit ifadeleri de bir sınıfın global düzeydeki elemanlarıdır. Yani bir nesne üzerinden const ifadelerine erişilemez. Statik değişkenlerde olduğu gibi sabit değişkenlere de sınıfın ismiyle erişilebilir.

Sabit ifadeleri referans tipinden olamaz. Çünkü referans tiplerinin değerleri çalışma zamanında ayarlanır.

Örneğin aşağıdaki kullanım geçersizdir,

class Sınıf
{
}
class Cebir
{
const Sınıf a = new Sınıf();
}

Ancak bu duruma bir istisna vardır. String türü referans türü olmasına rağmen eğer string türünden bir nesneyi new anahtar sözcüğü kullanmadan tanımlarsak değişkeni const olarak tanımlayabiliriz.

public const string a = "Berkan";

readonly

Referans tipleri için sabitleri tanımlamada readonly anahtar sözcüğü kullanılır. Ancak readonly olarak tanımlanan değişkenler global düzeyde olacak diye bir şey yoktur.

static elemanları readonly olarak tanımladığımızda const anahtar sözcüğünün referans tipleri için bir versiyonunu yapmış oluruz.

Not: static readonly ve const olarak tanımlanmış değişkenlerin tek farkı ilk değer verilme zamanlarıdır. const değişkenlere derleme zamanında static readonly değişkenlere ise çalışma zamanında ilk değer verilir.

Operatör Aşırı Yükleme(Operator Overloading)

Nesne yönelimli programlama tekniğinin en etkili özelliklerinden biri operatörlere sınıflarımız için yeni anlamlar yüklemektir. Sınıflarımız için tasarlayabileceğimiz en etkili üye elemanları belki operatör metotlarıdır. Operatör metotları bir nesnenin ifadeler içinde operatörlerle kullanıldığı zaman davranışını belirler. Örneğin int türünden nesneler için + operatörü iki sayının toplamı demektir. Aynı şekilde * operatörü de iki sayının çarpımı demektir. Temel veri türleri için operatörler zaten belirlenmiştir. Bu yüzden bunlara müdahale edemeyiz. Ancak kendi tasarladığımız sınıflar için operatörlere yeni anlamlar yükleyebiliriz.

Not: Operatör metotları ile yapabileceğimiz her şeyi aslında klasik metotlar ile de yapabiliriz. Ancak operator metotları sınıflarımızı aritmetik işlemler içeren ifadelerde rahatlıkla kullanmamızı sağlıyor.

Operator metotları ile ilgili uymamız gereken genel bilgiler.

  1. Operatör metotları static olarak tanımlanmalıdır.
  2. Operator metotlarının isimleri için operator anahtar sözcüğü kullanılır. Örneğin operator+, operator* gibi.
  3. Bütün operatör metotlarının mutlaka en az parametresi olmalıdır. İki parametresi olan operator metotları olabildiği gibi tek parametresi olan operatör metotları da olabilir.
  4. Operatör metotları da klasik metotlar gibi aşırı yüklenebilir.
  5. Tekil(unary) operatör metotlarında parametre mutlaka ilgili sınıf türünden olmalıdır. Binary(iki operand alan) operator metotlarında ise en az bir parametre ilgili sınıf türünden olmalıdır.
  6. Operator metotları ref ve out anahtar sözcüklerini kullanmamalıdır.

Operatörlerin aşırı yüklenmesi ile ilgili örnekleri incelemek isterseniz.

İndeksleyiciler(Indexers)

İndeksleyiciler genellikle sınıfımızın üye elemanlarından biri dizi ya da benzeri bir türden ise kullanışlı olmaktadır. Bir indeksleyici, bir sınıfı dizi şeklinde kullanabilmek ve bu sınıftan türetilen nesneleri dizinleyebilmek amacıyla kullanılır. Başka bir deyişle bir indeksleyici, nesnelere dizi gibi davranılabilmesini sağlar.

Aşağıdaki örnekte indeksleyicinin çalışma mantığını inceleyeceğiz.

class Indexer
{
private int[] dizi;
public Indexer(int DiziUzunluğu)
{
dizi = new int[DiziUzunluğu];
}

public int DiziBoyut
{
get
{
return dizi.Length;
}
}

public int this[int indeks]
{
get
{
return dizi[indeks];
}
set
{
dizi[indeks] = value;
}
}
}
class Indeksleyici
{
static void Main()
{
Indexer x = new Indexer(5);

for(int i = 0; i < x.DiziBoyut; ++i)
Console.WriteLine("i[{0}] = {1}", i, x[i]);
}
}

Indexer sınıfının yapıcı metodu ile dizi’ nin boyutu dinamik olarak belirleniyor. Dolayısıyla dizinin bütün elemanları varsayılan değere yani 0 değerine atanacaktır. Indexer türünden bir nesne oluşturum x[4] dediğimizde aslında Indexer sınıfındaki dizinin 4. elemanına ulaşıyoruz demektir. Yani indeksleyicilerle sınıflarımıza bir dizi görüntüsü verebiliriz.

Yapılar(Structs)

Yapılar C# dilinde değer tipi olan verilerdir. Nesnelere referans yolu ile erişmek bazı durumlarda avantajlı olmayabilir. Örneğin birbiri ile ilişkili(high cohesion) az sayıda değişkeni bir sınıf içinde tutmak bellek kullanımı açısından pek yararlı değildir. Referans tipleri için hem heap bölgesinde sınıfın üye elemanları için alan tahsis edilir hem de referans değerini tutmak için stack bölgesinde alan tahsis edilir. Heap bölgesindeki nesneye her ulaşmak istediğimizde ayrıca zaman geçeceği için az sayıda eleman içerecek ve sadece bir veri tipi olabilecek değişkenleri sınıf olarak tanımlamak yerine yapı olarak tanımlamak hız ve verimlilik açısından daha faydalıdır. Yapılar değer tipi oldukları için yapı türünden nesneler stack bellek bölgesinde saklanır. Genellikle birbiriyle ilişkili değişkenleri bir yapıda toplamak için kullanılır.

Bir yapı nesnesi tanımlama için yine new anahtar sözcüğü kullanılabilir. new anahtar sözcüğü kullanılınca yapının varsayılan yapıcı metodu ya da bizim tanımladığımız diğer yapıcı metotları çağırılır. new anahtar sözcüğünü kullanmadan da sınıflardan farklı olarak yapı nesnesi tanımlayabiliriz. Bu şekilde tanımlanan yapı nesnelerine ilk değer atanmayacağı için her bir üye elemana tek tek değer atanmalıdır. Hatılarsanız bu durum değer tipindeki temel veri türleri içinde geçerliydi. Buradan değer tipindeki veri türlerinin aslında birer struct olduğunu çıkarabiliriz.

Not: Yapıların da sınıflar gibi birden fazla yapıcı metotları olabilir. Ancak varsayılan yapıcıyı kendimiz bildiremeyiz. Yani yapılarda bildirilen bütün yapıcıların parametre alma zorunluluğu vardır.

Not: Yapıcı metot bildirildiği zaman yapının bütün elemanlarına ilk değer verme zorunluluğu vardır.

Avantajları

  1. Stack bellek bölgesinde bir değişken için alan ayırmak aynı işi heap bölgesinde yapmaktan daha hızlıdır.
  2. Sınıf nesneleri Garbage Collection mekanizması ile heap alanından silinmektedir. Bir sınıf nesnesi için Garbage Collection mekanizmasının ne zaman devreye gireceği kesin olarak belli değildir. Yani bir nesnenin faaliyet alanı bittiği anda yıkıcı metotlar çağrılmayabilir. Bu da programlarımızda nelerin olup bittiğini tam olarak anlayamamamıza neden olur. Ancak yapı nesnelerinde bu böyle değildir. Yapılar yıkıcı metotlar olmamasına rağmen yapı nesnesinin faaliyet alanı dışına çıkıldığında nesne bellekten otomatik silinir.
  3. Stack bölgesinde bulunan değişkenlerin kopyalanmasını daha hızlıdır.

--

--