Derinlemesine yazılım eğitimleri için kanalımı takip edebilirsiniz...

C#’ta ICloneable Interface’i İle Nesne Kopyalama

Merhaba,

Bu yazımızda C#’ta bir nesneyi kopyalamamıza yarayan ICloneable Interface’ini inceleyeceğiz. Tabi bu Interface’e gelmeden önce uzun uzun bir kaç hususta konuşalım diyorum…

C#’ta(ve Java vs. gibi popüler programlama dillerinde) bildiğimiz gibi değişkenler “Değer Tipli Değişkenler(Value Type Variable)” ve “Referans Tipli Değişkenler(References Type Variable)” olmak üzere ikiye ayrılmaktadırlar. Bu değişkenler arasındaki temel fark, değer tipli değişkenler belleğin Stack bölgesinde tutulurken, referans tipli değişkenler ise Heap bölgesinde tutulmaktadır.

Şimdi aşağıdaki durumu inceleyelim.

        static void Main(string[] args)
        {
            int Sayi1 = 10;
            int Sayi2 = Sayi1;
        }

Gördüğünüz gibi int tipinde iki değer tipli değişken arasında bir çalışma yaptık. “Sayi2” değişkenine, ‘=’ (Assign) operatörü ile “Sayi1” değişkenini atadık. Bu işlem yapılırken “Sayi1” değişkeninin yeni bir kopyası oluşturulmakta ve “Sayi2” değişkenine bu değişkenin değeri aktarılmaktadır. Buradan gelmek istediğim nokta ise; “Sayi2” değişkeninde yapılan herhangi bir değişiklik “Sayi1” değişkenini etkilemeyecektir.

        static void Main(string[] args)
        {
            int Sayi1 = 10;
            int Sayi2 = Sayi1;
            Console.WriteLine("Sayi2 değişkenin değeri : " + Sayi2);
            Console.WriteLine("Sayi1 değişkenin değeri : " + Sayi1);
            Sayi2 = 21;
            Console.WriteLine("Sayi2 değişkenin değeri : " + Sayi2);
            Console.WriteLine("Sayi1 değişkenin değeri : " + Sayi1);
        }

C#'ta ICloneable Interface'i İle Nesne Kopyalama

C#’ta ICloneable Interface’i İle Nesne Kopyalama


Yukarıdaki örnek kod bloğunun çıktısında da gördüğünüz gibi değer tipli değişkenlerde yukarıdaki satırlarda anlattığım durum geçerlidir.

Amma velakin referans tipli değişkenler için durum hiçte böyle değildir.
Örnek olarak elimizde aşağıdaki gibi bir sınıfımız olsun.

    class Araba
    {
        public int ArabaNo { get; set; }
        public string Marka { get; set; }
        public string Model { get; set; }
        public string KM { get; set; }
        public bool Vites { get; set; }
    }

Şimdi aşağıdaki durumu inceleyiniz.

        static void Main(string[] args)
        {
            Araba araba = new Araba();
            Araba _araba = araba;
        }

_araba referansına = operatörü ile araba referansı atanırsa, bu referanslara bağlı olan nesnelerin bellek üzerindeki adresleri kopyalanmaktadır. Yani aşağıdaki şemada olduğu gibi iki referansta aynı nesneyi göstermektedir.
C#'ta ICloneable Interface'i İle Nesne Kopyalama
Bu demek oluyor ki, _araba referansı üzerinde yaptığımız herhangi bir değişiklik, araba renferansınıda etkileyecektir.

        static void Main(string[] args)
        {
            Araba araba = new Araba() { ArabaNo = 1, KM = "0", Marka = "Opel", Model = "Astra", Vites = true };

            Console.WriteLine("Araba No : " + araba.ArabaNo + "\nKM : " + araba.KM + "\nMarka : " + araba.Marka + "\nModel : " + araba.Model + "\nVites : " + araba.Vites);
            Console.WriteLine("**************");

            Araba _araba = araba;
            _araba.ArabaNo = 1;
            _araba.KM = "10";
            _araba.Marka = "Opel";
            _araba.Model = "Corsa";
            _araba.Vites = false;

            Console.WriteLine("Araba No : " + araba.ArabaNo + "\nKM : " + araba.KM + "\nMarka : " + araba.Marka + "\nModel : " + araba.Model + "\nVites : " + araba.Vites);

            Console.WriteLine("**************");

            Console.WriteLine("Araba No : " + _araba.ArabaNo + "\nKM : " + _araba.KM + "\nMarka : " + _araba.Marka + "\nModel : " + _araba.Model + "\nVites : " + _araba.Vites);
        }

Yukarıdaki kod bloğu, yaptığımız açıklamada olduğu gibi aşağıdaki sonucu verecektir.
C#'ta ICloneable Interface'i İle Nesne Kopyalama

Referans tipli değişkenlerin birbirlerine atanması durumunda bellekteki adreslerin kopyalanmasına Shallow Copy denmektedir. Aslında, referans tiplerde = operatörü ile atama yapıldığında, arka tarafta Object sınıfından miras alınan, MemberwiseClone isimli metod çağrılmaktadır. İşte bu metod referans tiplerin atanması için Shallow Copy gerçekleştirir. Yani referansların değerleri değil, bellek üzerindeki adresleri kopyalandığından dolayı Shallow Copy yani Sığ Kopyalama veyahut Yüzeysel Kopyalama denmektedir.

Eğer ki biz; Immutable bir nesne oluşturarak, yani ilgili nesneden yeni bir kopya oluşturup o kopyayı atamayı istiyorsak işte bu yazımızın asıl içeriğiyle alakalı satırlarına gelmiş bulunmaktayız.

Haliyle başlıktan da anlaşılacağı gibi ICloneable Interface’i elimizdeki nesneleri kopyalamamızı sağlayan bir arayüz görevi görmektedir.

Nesnelerin kopyalanması işlemine “Deep Copy” adı verilir.

Tabi öncelikle ICloneable Interface’ini kullanmadan elimizdeki nesneyi başka nasıl kopyalayabiliriz inceleyelim. Örneğimizi yukarıda oluşturduğumuz Araba sınıfı üzerinde gerçekleştireceğiz.

    class Araba
    {
        public int ArabaNo { get; set; }
        public string Marka { get; set; }
        public string Model { get; set; }
        public string KM { get; set; }
        public bool Vites { get; set; }

        public Araba Copy()
        {
            return new Araba
            {
                ArabaNo = this.ArabaNo,
                Marka = this.Marka,
                Model = this.Model,
                KM = this.KM,
                Vites = this.Vites
            };
        }
    }

Yukarıdaki kod bloğunda gördüğünüz gibi ilgili sınıf içerisine Copy isminde bir metod tanımlayarak geriye aynı tipte bir nesne döndürebiliriz. Haliyle o anki nesne, yeni oluşturacağı nesneye kendi property değerlerini aktaracak ve geriye kopyalanmış gibi aynı değerleri taşıyan bir vaziyette dönecektir.

ya da aşağıdaki örneği inceleyiniz.

    class Araba
    {
        public int ArabaNo { get; set; }
        public string Marka { get; set; }
        public string Model { get; set; }
        public string KM { get; set; }
        public bool Vites { get; set; }

        public Araba Copy()
        {
            return (Araba)this.MemberwiseClone();
        }
    }

Yazımızın yukarıdaki satırlarında bahsettiğim MemberwiseClone metodu aracılığıyla da ilgili nesnemizi kopyalıp geriye döndürebiliriz. Dikkat edersek, o anki nesnenin MemberwiseClone metodu ile copyasını object olarak elde ediyor, cast ederek geriye döndürüyoruz.

İki işlem içinde aşağıdaki kullanım aynı sonucu verecektir.

        static void Main(string[] args)
        {
            Araba araba = new Araba();
            Araba _araba = araba.Copy();
            if (araba.Equals(_araba))
                Console.WriteLine("Nesneler aynı");
            else
                Console.WriteLine("Nesneler farklı");
        }

C#'ta ICloneable Interface'i İle Nesne Kopyalama

Aynı işi ICloneable Interface’i ilede aşağıdaki gibi gerçekleştirebilmekteyiz.

    class Araba : ICloneable
    {
        public int ArabaNo { get; set; }
        public string Marka { get; set; }
        public string Model { get; set; }
        public string KM { get; set; }
        public bool Vites { get; set; }

        public object Clone()
        {
            return this.MemberwiseClone();
        }
    }

Gördüğünüz gibi IConeable Interface’ini uyguladığımızda Clone metodunu implement ettirmektedir. Bu metod içerisinde de MemberwiseClone metodu sayesinde nesnemizin kopyasını object olarak göndermekteyiz.

        static void Main(string[] args)
        {
            Araba araba = new Araba();
            Araba _araba = (Araba)araba.Clone();
            if (araba.Equals(_araba))
                Console.WriteLine("Nesneler aynı");
            else
                Console.WriteLine("Nesneler farklı");
        }

Clone nesnesinden gelen nesneyi cast ederek elde etmemiz gerekecektir.

Ve sonuç gene aynı olacaktır.
C#'ta ICloneable Interface'i İle Nesne Kopyalama

Okuduğunuz için teşekkür ederim…

Sonraki yazılarımda görüşmek üzere…
İyi çalışmalar…

Bunlar da hoşunuza gidebilir...

1 Cevap

  1. 09 Nisan 2016

    […] C#’ta ICloneable Interface’i İle Nesne Kopyalama başlıklı yazımı incelerseniz eğer, ICloneable Interface’ini kullanarak bir nesne kopyalamayı inceleyebilirsiniz. […]

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir