Menu
Coddy logo textTech

Polimorfizm czasu kompilacji a czasu wykonania

Część sekcji Programowanie obiektowe ścieżki C# w Coddy. Lekcja 25 z 70.

Polimorfizm oznacza „wiele form” — zdolność tego samego kodu do różnego działania w zależności od kontekstu. C# obsługuje dwa odrębne typy polimorfizmu, a zrozumienie, kiedy każdy z nich jest rozstrzygany, pomaga pisać bardziej elastyczny kod.

Polimorfizm czasu kompilacji (nazywany również polimorfizmem statycznym) jest rozstrzygany przez kompilator przed uruchomieniem programu. Przeciążanie metod to główny przykład — wiele metod ma tę samą nazwę, ale różne parametry:

public class Calculator
{
    public int Add(int a, int b) => a + b;
    public double Add(double a, double b) => a + b;
}

var calc = new Calculator();
calc.Add(5, 3);       // Kompilator wybiera wersję int
calc.Add(5.0, 3.0);   // Kompilator wybiera wersję double

Kompilator analizuje typy argumentów i wybiera właściwą metodę podczas kompilacji. Ta decyzja zostaje podjęta przed uruchomieniem programu.

Polimorfizm czasu wykonania (polimorfizm dynamiczny) jest rozstrzygany podczas działania programu. Dzieje się tak w przypadku metod virtual i override — rzeczywisty typ obiektu określa, która metoda zostanie wykonana:

Animal pet = new Dog();  // Zadeklarowany jako Animal, w rzeczywistości jest Dog
pet.Speak();             // Wywołuje metodę Speak() klasy Dog w czasie działania programu

Kompilator nie wie, które Speak() zostanie uruchomione — ta decyzja zapada w czasie wykonywania programu na podstawie rzeczywistego typu obiektu. To właśnie sprawia, że polimorfizm oparty na dziedziczeniu jest tak potężnym narzędziem do tworzenia elastycznych i rozszerzalnych systemów.

challenge icon

Wyzwanie

Łatwy

Zbudujmy system konwersji, który pokaże w praktyce oba rodzaje polimorfizmu. Utworzysz klasę wykorzystującą przeciążanie metod (polimorfizm czasu kompilacji), a także hierarchię dziedziczenia wykorzystującą metody virtual/override (polimorfizm czasu wykonywania).

Rozmieścisz swój kod w czterech plikach:

  • Converter.cs: Zdefiniuj klasę Converter w przestrzeni nazw Conversion. Ta klasa demonstruje polimorfizm czasu kompilacji przez przeciążanie metod. Utwórz trzy przeciążone metody Convert:
    • Convert(int value) zwraca "Integer: {value}"
    • Convert(double value) zwraca "Double: {value}"
    • Convert(string value) zwraca "String: {value}"
  • Shape.cs: Zdefiniuj klasę bazową Shape w przestrzeni nazw Conversion. Ta klasa ma właściwość Name (string) oraz konstruktor, który ją ustawia. Dodaj metodę virtual o nazwie Describe(), która zwraca "This is a {Name}".
  • Circle.cs: Zdefiniuj klasę Circle w przestrzeni nazw Conversion, która dziedziczy po Shape. Dodaj właściwość Radius (double). Konstruktor przyjmuje promień i przekazuje "Circle" do konstruktora bazowego. Nadpisz Describe(), aby zwracała "This is a Circle with radius {Radius}".
  • Program.cs: W głównym pliku zademonstruj oba rodzaje polimorfizmu. Najpierw utwórz obiekt Converter i wywołaj wszystkie trzy przeciążone metody z wartościami wejściowymi. Następnie utwórz obiekt Circle, przechowaj go w zmiennej typu Shape i wywołaj Describe(), aby pokazać polimorfizm czasu wykonywania.

Otrzymasz cztery dane wejściowe:

  • Wartość całkowitą
  • Wartość typu double
  • Wartość tekstową
  • Promień okręgu (double)

Wypisz wynik w następującym formacie:

Compile-time Polymorphism:
{Convert(int) result}
{Convert(double) result}
{Convert(string) result}
Runtime Polymorphism:
{Describe() result from Shape variable holding Circle}

Na przykład, jeśli dane wejściowe to 42, 3.14, Hello i 5.5, wynik powinien wyglądać następująco:

Compile-time Polymorphism:
Integer: 42
Double: 3.14
String: Hello
Runtime Polymorphism:
This is a Circle with radius 5.5

Zwróć uwagę na kluczową różnicę: kompilator decyduje, którą metodę Convert wywołać na podstawie typów argumentów w czasie kompilacji, natomiast metoda Describe() jest rozstrzygana w czasie wykonywania na podstawie rzeczywistego typu obiektu, nawet jeśli jest on przechowywany w zmiennej typu Shape!

Spróbuj swoich sił

using System;
using Conversion;

class Program
{
    public static void Main(string[] args)
    {
        // Wczytaj dane wejściowe
        int intValue = Convert.ToInt32(Console.ReadLine());
        double doubleValue = Convert.ToDouble(Console.ReadLine());
        string stringValue = Console.ReadLine();
        double radius = Convert.ToDouble(Console.ReadLine());

        // TODO: Zademonstruj polimorfizm statyczny
        // Utwórz obiekt Converter i wywołaj wszystkie trzy przeciążone metody Convert
        Console.WriteLine("Compile-time Polymorphism:");
        // Wywołaj Convert z argumentami intValue, doubleValue i stringValue

        // TODO: Zademonstruj polimorfizm dynamiczny
        // Utwórz obiekt Circle i przypisz go do zmiennej typu Shape
        // Następnie wywołaj Describe() na zmiennej typu Shape
        Console.WriteLine("Runtime Polymorphism:");
        // Utwórz obiekt Circle i wywołaj Describe()
    }
}
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator C# online