Полиморфизм в C#: статический и динамический, перегрузка и переопределение
Что такое полиморфизм
Полиморфизм («много форм») — принцип ООП: «один интерфейс, множество реализаций». В C# бывает двух видов:
- Статический (compile-time) — связывание метода происходит на этапе компиляции
- Динамический (run-time) — связывание происходит во время выполнения
Статический полиморфизм
1. Перегрузка методов (Method Overloading)
Несколько методов с одинаковым именем, но разными сигнатурами (тип/число параметров). Тип возврата НЕ учитывается.
public class Printer
{
public void Print(int i) => Console.WriteLine($"Int: {i}");
public void Print(double d) => Console.WriteLine($"Double: {d}");
public void Print(string s) => Console.WriteLine($"String: {s}");
// public void Print(float f) => ... // тоже можно
}
// Использование
Printer p = new Printer();
p.Print(5); // Int: 5
p.Print(500.263); // Double: 500.263
p.Print("Hello"); // String: Hello
2. Перегрузка операторов (Operator Overloading)
Определение поведения операторов (+, -, ==, != и др.) для пользовательских типов. См. отдельную статью.
Динамический полиморфизм
Абстрактные классы и методы
abstract class— не может быть инстанцирован, может содержать abstract-членыabstractметод — только объявление, реализация в наследнике- abstract-класс не может быть
sealed
public abstract class Shape
{
public abstract double Area(); // без тела
}
public class Rectangle : Shape
{
public double Width { get; set; }
public double Height { get; set; }
public override double Area() => Width * Height; // ОБЯЗАТЕЛЬНО override
}
Shape s = new Rectangle { Width = 10, Height = 7 };
Console.WriteLine(s.Area()); // 70 — вызов реализации Rectangle
Виртуальные методы (virtual / override)
virtual — есть реализация по умолчанию, МОЖНО переопределить.
override — предоставляет новую реализацию.
public class Shape
{
protected double Width, Height;
public virtual double Area()
{
Console.WriteLine("Base Area");
return 0;
}
}
public class Rectangle : Shape
{
public override double Area()
{
Console.WriteLine("Rectangle Area");
return Width * Height;
}
}
public class Triangle : Shape
{
public override double Area()
{
Console.WriteLine("Triangle Area");
return Width * Height / 2;
}
}
// Полиморфный вызов
void PrintArea(Shape shape)
{
Console.WriteLine($"Area: {shape.Area()}"); // динамическое связывание
}
PrintArea(new Rectangle { Width = 10, Height = 7 }); // Rectangle Area, 70
PrintArea(new Triangle { Width = 10, Height = 5 }); // Triangle Area, 25
Ключевые отличия
| Характеристика | Статический (перегрузка) | Динамический (переопределение) |
|---|---|---|
| Время связывания | Компиляция | Выполнение |
| Механизм | Несколько методов с одним именем | virtual/override/abstract |
| Сигнатура | Должна отличаться | Должна совпадать |
| Пример | Print(int), Print(string) | Area() в Shape → Rectangle |
Sealed — запрет наследования/переопределения
public sealed class FinalClass { } // нельзя наследовать
public class Base
{
public virtual void Method() { }
public virtual void Another() { }
}
public class Derived : Base
{
public sealed override void Method() { } // нельзя переопределять дальше
public override void Another() { } // можно
}
Pattern matching и is/as (современный полиморфизм)
// is с pattern
if (shape is Rectangle r)
Console.WriteLine(r.Width);
// switch expression
string desc = shape switch
{
Rectangle r => $"Rect {r.Width}x{r.Height}",
Circle c => $"Circle r={c.Radius}",
_ => "Unknown"
};
Язык C
- Классы и объекты в C#: Фундаменты надёжного ООП
- Модификаторы доступа в C#: public, private, protected, internal и другие
- Ключевое слово static в C#: статические переменные, методы и классы
- Абстрактные классы и методы в C#: практическое руководство
- Вложенные классы в C#: определение, использование и наследование
- Частичные классы и методы в C#: понимание и применение
- Шаблоны классов в C++: практическое руководство
- Анонимные внутренние классы в Java: определение, синтаксис и практические примеры
- Освоение Java ObjectOutputStream: сериализация, методы и практические примеры
- Освоение Java Generics: создание переиспользуемого, типобезопасного кода