Moja dva centa za Deep copy vs Shallow copy u .Netu

Microsoft .Net pruža podršku za kloniranje objekata - mogućnost stvaranja točne kopije objekta (također poznatog kao klon). Kloniranje može biti dvije vrste: plitka kopija i duboka kopija. Iako se prva može implementirati pozivom na metodu MemberwiseClone klase System.Object, implementacija potonje pomalo je nezgodna jer za nju u zadanom nemate podršku. U osnovi, dok plitka kopija kopira reference bez referenciranih objekata, duboki klon stvara kopiju izvornog objekta zajedno sa svojim referencama.

Koje su sve dostupne opcije za kloniranje?

Da biste klonirali primjerak klase u C #, imate nekoliko opcija koje možete odabrati. To uključuje sljedeće:

  • Korištenje metode System.Object.MemberwiseClone za izvođenje plitke kopije
  • Korištenje Reflection-a iskorištavanjem prednosti metode Activator.CreateInstance
  • Korištenje serializacije
  • Implementacijom IClonable sučelja

Imajte na umu da prilikom kloniranja objekata ili primjera klasa u .Netu ne morate uzimati u obzir statičke članove ili statička polja. Razlog je taj što su statični objekti pohranjeni na dijeljenoj memoriji i za njih imate dodijeljeno jedno memorijsko mjesto po domeni aplikacije.

Plitka kopija nasuprot dubokoj kopiji

Razmotrimo klasu Employee i stvorimo instancu klase Employee kako je prikazano u nastavku.

Employee emp = new Employee();

Employee clone = emp;

Pogledajte isječak koda gore. Operator dodjele "=" kopirao bi referencu, a ne stvarni objekt. Metoda MemberwiseClone () definirana u klasi System.Object čini potpuno istu stvar. Ovo su primjeri plitke kopije. Stoga, kada koristite operator dodjele za kopiranje i prigovor drugom ili, koristite metodu Memberwise.Clone (), zapravo radite plitku kopiju objekta.

Dok se u plitkoj kopiji članovi kopiranog objekta odnose na isti objekt kao i izvorni objekt, u dubinskoj se kopiji u novoj ili kloniranoj instanci kreiraju zasebne instance svakog člana referentnog tipa u izvornoj instanci. Dakle, ako imate referentni tip u izvornoj instanci, novi će primjer u sebi sadržavati isti član referentnog tipa, ali ovaj će referentni tip ukazivati ​​na potpuno novu instancu.

U plitkoj kopiji stvara se novi objekt, a zatim se nestatični članovi izvornog objekta kopiraju u ciljni objekt ili novi objekt. Ako je član polje vrste vrijednosti, izvodi se kopija polja po bit. Suprotno tome, ako je član koji se kopira referentna vrsta, referenca se kopira. Stoga se referentni član unutar izvornog objekta i ciljni objekti odnose na isti objekt u memoriji.

Ako unutar sebe imate zbirku s pojedinačnim elementima i željeli biste izvesti plitku kopiju instance zbirke. Treba napomenuti da plitka kopija instance zbirke kopira strukturu zbirke, ali ne i elemente unutar zbirke. Stoga, nakon što napravite plitku kopiju instance zbirke, imali biste dvije zbirke koje dijele pojedinačne elemente zbirke. Naprotiv, ako napravite dubinsku kopiju instance zbirke, imali biste dvije instance zbirke s dupliciranim pojedinačnim elementima izvorne zbirke.

Implementacija dubinske kopije pomoću serializacije

Dubinsku kopiju možete implementirati na više načina. Jedan od najpoželjnijih načina implementacije dubinske kopije objekta je upotreba serializacije. Također možete iskoristiti refleksiju za izvođenje dubinske kopije instance klase. Sljedeći isječak koda ilustrira kako možete napisati metodu koja implementira binarnu serializaciju za izvođenje dubinske kopije instance pomoću C #.

public static T DeepCopy(T obj)

       {

           if (!typeof(T).IsSerializable)

           {

               throw new Exception("The source object must be serializable");

           }

           if (Object.ReferenceEquals(obj, null))

           {

               throw new Exception("The source object must not be null");

           }

           T result = default(T);

           using (var memoryStream = new MemoryStream())

           {

                var formatter = new BinaryFormatter();

               formatter.Serialize(memoryStream, obj);

               memoryStream.Seek(0, SeekOrigin.Begin);

               result = (T)formatter.Deserialize(memoryStream);

               memoryStream.Close();

           }

           return result;

       }

Uzimajući u obzir da imate klasu entiteta koja se zove Employee, možete izvesti dubinsku kopiju instance klase Employee kako je prikazano u isječku koda u nastavku.

static void Main(string[] args)

       {

           Employee emp = new Employee();

           emp.EmployeeId = 1;

           emp.FirstName = "Joydip";

           emp.LastName = "Kanjilal";

           Employee clone = DeepCopy(emp);

           if(Object.ReferenceEquals(emp, clone))

           {

               Console.WriteLine("References are the same.");

           }

           else

           {

               Console.WriteLine("References are different.");

           }

       }

Kada izvršite gornji program, izradit će se dubinska kopija instance "emp" i poruka "Reference su različite". prikazat će se.