Zrozumienie natury typów referencyjnych oraz różnicy między kopiowaniem płytkim a głębokim. Student nauczy się korzystać z metody MemberwiseClone(), implementować własne metody klonowania oraz weryfikować tożsamość obiektów za pomocą ReferenceEquals().
W komisie "Auto-Premium" pojawia się potrzeba kopiowania danych pojazdów (np. gdy mamy dwa niemal identyczne modele na stanie). Szybko odkrywasz, że zwykłe przypisanie auto2 = auto1 nie tworzy nowego samochodu, a jedynie drugą nazwę dla tego samego obiektu w pamięci. Co więcej, dodając do auta szczegółowe informacje o silniku (osobny obiekt), zauważasz, że nawet użycie standardowych mechanizmów kopiowania może być mylące.
Jeśli zmienisz moc silnika w pozornie nowej "kopii", zmieni się ona również w "oryginale"! To zjawisko nazywamy kopiowaniem płytkim (shallow copy) – skopiowane zostały wartości pól prostych, ale pola będące obiektami wciąż wskazują na te same miejsca w pamięci. Musisz zaprojektować mechanizm kopiowania głębokiego (deep copy), który zapewni pełną niezależność obu pojazdów. Twoim zadaniem jest stworzenie metody, która nie tylko powieli dane samochodu, ale również stworzy zupełnie nowy, oddzielny obiekt silnika dla każdego auta.
using System;
namespace LaboratoriumOOP
{
// Klasa pomocnicza reprezentująca obiekt składowy (pole referencyjne)
public class Silnik
{
public int Moc { get; set; }
public Silnik(int moc) { Moc = moc; }
}
public class Samochod
{
public string Model { get; set; }
public Silnik DaneSilnika { get; set; }
public Samochod(string model, int mocSilnika)
{
Model = model;
DaneSilnika = new Silnik(mocSilnika);
}
// KOPIOWANIE PŁYTKIE (Shallow Copy)
// Kopiuje wartości pól bit po bicie. Dla typów referencyjnych (Silnik)
// kopiuje tylko ADRES, a nie cały obiekt.
public Samochod KlonujPlytko()
{
return (Samochod)this.MemberwiseClone();
}
// KOPIOWANIE GŁĘBOKIE (Deep Copy)
// Tworzy całkowicie nowy graf obiektów w pamięci.
public Samochod KlonujGleboko()
{
Samochod nowy = (Samochod)this.MemberwiseClone();
// Ręczne klonowanie obiektów referencyjnych:
nowy.DaneSilnika = new Silnik(this.DaneSilnika.Moc);
return nowy;
}
public void Info(string nazwa)
{
Console.WriteLine($"{nazwa}: {Model}, Moc silnika: {DaneSilnika.Moc} KM");
}
}
class Program
{
static void Main()
{
Console.WriteLine("--- ZADANIE 04: Mechanizmy kopiowania obiektów ---\n");
Samochod oryginal = new Samochod("Audi RS6", 600);
// 1. Kopiowanie płytkie
Samochod kopiaPlytka = oryginal.KlonujPlytko();
// 2. Kopiowanie głębokie
Samochod kopiaGleboka = oryginal.KlonujGleboko();
Console.WriteLine("Stan początkowy:");
oryginal.Info("Oryginał");
Console.WriteLine("\n--- ZMIANA MOCY W KOPIACH ---");
kopiaPlytka.DaneSilnika.Moc = 150; // Zmieniamy w płytkiej kopii
kopiaGleboka.DaneSilnika.Moc = 900; // Zmieniamy w głębokiej kopii
Console.WriteLine("\nEfekt zmiany w pamięci:");
oryginal.Info("Oryginał");
kopiaPlytka.Info("Kopia Płytka");
kopiaGleboka.Info("Kopia Głęboka");
Console.WriteLine("\n--- WERYFIKACJA TOŻSAMOŚCI (ReferenceEquals) ---");
Console.WriteLine("Czy kopia płytka to ten sam obiekt? " +
object.ReferenceEquals(oryginal, kopiaPlytka));
Console.WriteLine("Czy ich silniki to ten sam obiekt (kopia płytka)? " +
object.ReferenceEquals(oryginal.DaneSilnika, kopiaPlytka.DaneSilnika));
Console.WriteLine("Czy ich silniki to ten sam obiekt (kopia głęboka)? " +
object.ReferenceEquals(oryginal.DaneSilnika, kopiaGleboka.DaneSilnika));
Console.WriteLine("\nWNIOSEK: Kopiowanie płytkie współdzieli obiekty składowe.");
Console.WriteLine("Kopiowanie głębokie zapewnia pełną izolację danych.");
Console.ReadKey();
}
}
}