Zrozumienie koncepcji polimorfizmu dynamicznego i późnego wiązania (late binding). Student nauczy się korzystać ze słów kluczowych virtual oraz override, a także pozna operatory bezpiecznego rzutowania is oraz as do sprawdzania typów w czasie wykonywania programu.
W Twoim prężnie działającym komisie "Auto-Premium" każdy pojazd, zanim trafi na wystawę, musi przejść procedurę przygotowania. Jednak proces ten wygląda zupełnie inaczej dla samochodu, który wymaga mycia tapicerki i woskowania karoserii, a inaczej dla motocykla, gdzie kluczowe jest sprawdzenie naciągu łańcucha i polerowanie chromów. Zamiast pisać oddzielne pętle dla każdego typu pojazdu, chcesz po prostu wywołać wspólną komendę "PrzygotujDoSprzedazy()" dla całej floty.
To właśnie tutaj polimorfizm pokazuje swoją potęgę: jeden komunikat wysłany do grupy różnych obiektów wywołuje u każdego z nich specyficzną, odpowiednią dla jego typu reakcję. System sam "wie", którą wersję metody wywołać, mimo że operujemy na ogólnej liście pojazdów. W tym zadaniu nauczysz się również, jak bezpiecznie sprawdzać, z jakim typem pojazdu masz w danej chwili do czynienia (używając operatorów is i as), aby móc wykonać dodatkowe operacje dostępne tylko dla konkretnych podtypów.
using System;
using System.Collections.Generic;
namespace LaboratoriumOOP
{
public class Pojazd
{
public string Marka { get; protected set; }
public Pojazd(string marka) { Marka = marka; }
// VIRTUAL: Metoda wirtualna posiada domyślną implementację,
// ale może zostać nadpisana w klasie pochodnej.
public virtual void PrzygotujDoSprzedazy()
{
Console.WriteLine($"[POJAZD] {Marka}: Sprawdzanie poziomu płynów eksploatacyjnych...");
}
}
public class Samochod : Pojazd
{
public Samochod(string marka) : base(marka) { }
// OVERRIDE: Nadpisanie metody wirtualnej.
public override void PrzygotujDoSprzedazy()
{
base.PrzygotujDoSprzedazy(); // Wywołanie logiki z klasy bazowej
Console.WriteLine($"[SAMOCHÓD] {Marka}: Mycie karoserii i odkurzanie wnętrza.");
}
public void OtworzBiezacyProjekt()
{
Console.WriteLine(" -> Specjalna funkcja dostępna tylko dla komputerów pokładowych aut.");
}
}
public class Motocykl : Pojazd
{
public Motocykl(string marka) : base(marka) { }
public override void PrzygotujDoSprzedazy()
{
base.PrzygotujDoSprzedazy();
Console.WriteLine($"[MOTOCYKL] {Marka}: Smarowanie łańcucha i polerowanie chromowanych elementów.");
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("--- ZADANIE 06: Polimorfizm dynamiczny i rzutowanie ---\n");
List placKomisowy = new List
{
new Samochod("Toyota"),
new Motocykl("Honda"),
new Samochod("Mercedes")
};
Console.WriteLine("1. Proces przygotowania całej floty (Polimorfizm):");
foreach (var pojazd in placKomisowy)
{
// Wywołanie polimorficzne: program sam decyduje w czasie runtime,
// którą wersję metody PrzygotujDoSprzedazy wywołać.
pojazd.PrzygotujDoSprzedazy();
Console.WriteLine("------------------------------------------");
}
Console.WriteLine("\n2. Wyszukiwanie specyficznych typów (Rzutowanie):");
foreach (var p in placKomisowy)
{
// OPERATOR 'is': Sprawdza czy obiekt jest zgodny z typem
if (p is Samochod s)
{
Console.WriteLine($"Zaleziono auto: {s.Marka}. Wykonuję akcje dodatkowe...");
s.OtworzBiezacyProjekt();
}
// OPERATOR 'as': Bezpieczne rzutowanie (zwraca null jeśli typy nie pasują)
Motocykl m = p as Motocykl;
if (m != null)
{
Console.WriteLine($"Znaleziono motocykl: {m.Marka}. Wykryto typ: {m.GetType().Name}");
}
}
Console.WriteLine("\n3. Porównanie typów (typeof vs GetType):");
if (placKomisowy[0].GetType() == typeof(Samochod))
{
Console.WriteLine("Pierwszy obiekt na liście jest dokładnie typu Samochod.");
}
Console.WriteLine("\nNaciśnij klawisz...");
Console.ReadKey();
}
}
}