Programavimas

Mano du centai „Deep copy“ ir „Shallow“ kopijose „.Net“

„Microsoft .Net“ teikia objektų klonavimo palaikymą - galimybę sukurti tikslią objekto kopiją (dar vadinamą klonu). Klonavimas gali būti dviejų tipų: sekli ir gili kopija. Nors pirmasis gali būti įgyvendinamas iškviečiant sistemos „MemberwiseClone“ metodą. Objektas, pastarosios įdiegimas yra šiek tiek sudėtingas, nes pagal numatytuosius nustatymus neturite to palaikymo sistemoje. Iš esmės, nors seklus egzempliorius nukopijuoja nuorodas be nurodytų objektų, gilus klonas sukuria šaltinio objekto kopiją kartu su nuorodomis.

Kokios yra visos galimos klonavimo galimybės?

Norėdami klonuoti klasės egzempliorių C #, galite pasirinkti keletą variantų. Tai apima:

  • Naudojant „System.Object.MemberwiseClone“ metodą seklioms kopijoms atlikti
  • „Reflection“ naudojimas pasinaudojant „Activator.CreateInstance“ metodu
  • Serializacijos naudojimas
  • Įdiegus „IClonable“ sąsają

Atkreipkite dėmesį, kad klonuojant objektus ar klasių egzempliorius .Net, nereikia atsižvelgti į statinius narius ar statinius laukus. Priežastis ta, kad statiniai objektai yra saugomi bendrosios atminties vietoje, o kiekvienai programos sričiai jiems skirta viena atminties vieta.

Sekli ir gili kopija

Apsvarstykite klasės darbuotoją ir mes sukursime darbuotojų klasės egzempliorių, kaip parodyta žemiau.

Darbuotojo emp = naujas darbuotojas ();

Darbuotojo klonas = emp;

Žr. Aukščiau pateiktą kodo fragmentą. Priskyrimo operatorius "=" nukopijuos nuorodą, o ne faktinį objektą. „MemberwiseClone“ () metodas, apibrėžtas sistemoje.Object, daro tą patį. Tai yra negilios kopijos pavyzdžiai. Taigi, kai naudojate priskyrimo operatorių, norėdami nukopijuoti ir prieštarauti kitam, arba naudodami „Memberwise.Clone (“) metodą, jūs iš tikrųjų darote negilų objekto kopiją.

Jei negiliai kopijuojant, nukopijuoto objekto nariai nurodo tą patį objektą kaip ir originalus objektas, giliojoje kopijoje kiekvienam iš pirminio egzemplioriaus referencinio tipo narių egzemplioriai sukuriami naujame arba klonuotame egzemplioriuje. Taigi, jei turite nuorodos tipą pradiniame egzemplioriuje, naujajame egzemplioriuje taip pat bus tas pats nuorodos tipo narys, tačiau šis nuorodos tipas nurodys visiškai naują egzempliorių.

Negilioje kopijoje sukuriamas naujas objektas, o tada nestatiniai šaltinio objekto nariai nukopijuojami į tikslinį objektą arba naują objektą. Jei narys yra vertės tipo laukas, atliekama lauko kopija po truputį. Priešingai, jei kopijuojamas narys yra nuorodos tipas, nuoroda nukopijuojama. Vadinasi, pirminio objekto ir tikslinių objektų viduje esantis referencinis narys nurodo tą patį objektą atmintyje.

Jei turite kolekciją su atskirais elementais viduje ir norėtumėte atlikti negilų rinkinio egzempliorių. Pažymėtina, kad sekli kolekcijos egzempliorius nukopijuoja kolekcijos struktūrą, bet ne kolekcijos viduje esančius elementus. Taigi, atlikę negilų kolekcijos egzempliorių, turėtumėte dvi kolekcijas, dalijančias atskirus kolekcijos elementus. Priešingai, jei atliksite gilią kolekcijos egzemplioriaus kopiją, turėtumėte du rinkimo egzempliorius, kurių atskirieji originalo kolekcijos elementai būtų dubliuoti.

Giliosios kopijos diegimas naudojant serijinį

Giliąją kopiją galite įdiegti įvairiais būdais. Vienas iš labiausiai pageidaujamų būdų įgyvendinti gilią objekto kopiją yra serizavimas. Taip pat galite pasinaudoti atspindžiu, kad atliktumėte gilią klasės egzemplioriaus kopiją. Šis kodo fragmentas parodo, kaip galite parašyti metodą, įgyvendinantį dvejetainį serializavimą, norint atlikti gilią egzemplioriaus kopiją naudojant C #.

viešoji statinė „T DeepCopy“ (T obj)

       {

jei (! typeof (T). Yra serijinis)

           {

mesti naują išimtį („Šaltinio objektas turi būti serijinis“);

           }

jei (Object.ReferenceEquals (obj, null))

           {

mesti naują išimtį ("šaltinio objektas neturi būti nulinis");

           }

T rezultatas = numatytasis (T);

naudojant (var memoryStream = new MemoryStream ())

           {

var formatter = new BinaryFormatter ();

formatuoti.Serializuoti (memoryStream, obj);

memoryStream.Seek (0, SeekOrigin.Begin);

rezultatas = (T) formatavėjas. Išimkite iš „MemoryStream“;

memoryStream.Close ();

           }

grąžinimo rezultatas;

       }

Atsižvelgdami į tai, kad turite objekto klasę, vadinamą „Darbuotojas“, galite atlikti „Employee“ klasės egzemplioriaus gilią kopiją, kaip parodyta toliau pateiktame kodo fragmente.

static void Main (string [] args)

       {

Darbuotojo emp = naujas darbuotojas ();

emp.EmployeeId = 1;

emp.FirstName = "Joydipas";

emp.LastName = "Kanjilal";

Darbuotojo klonas = „DeepCopy“ (emp);

jei (Object.ReferenceEquals (emp, klonas))

           {

Console.WriteLine ("Nuorodos yra tos pačios.");

           }

Kitas

           {

Console.WriteLine ("Nuorodos skiriasi.");

           }

       }

Kai vykdote aukščiau nurodytą programą, bus atlikta gili egzemplioriaus „emp“ kopija ir pranešimas „Nuorodos skiriasi“. bus rodomas.