Какво е интерфейс
Интерфейсът е „договор" — списък с методи и свойства, които всеки клас, който го имплементира, трябва да предостави. Не съдържа никаква логика — само сигнатури.
interface IShape
{
double Area();
double Perimeter();
}
class Circle : IShape
{
public double Radius;
public double Area() => Math.PI * Radius * Radius;
public double Perimeter() => 2 * Math.PI * Radius;
}
class Rectangle : IShape
{
public double Width, Height;
public double Area() => Width * Height;
public double Perimeter() => 2 * (Width + Height);
}Бележка
По конвенция имената на интерфейсите в C# започват с главно I — IShape, IComparable, IDisposable.
Защо интерфейси, ако имаме абстрактни класове
| Абстрактен клас | Интерфейс | |
|---|---|---|
| Може ли да съдържа логика? | Да — обикновени методи + полета | Не (или само default методи в нови версии) |
| Колко наследяваш? | Само ЕДИН (single inheritance) | Колкото искаш (multi inheritance) |
| Кога ползваш? | Споделена логика между сходни класове | Договор/способност, която сходни-или-различни класове предоставят |
| Пример | Animal → Dog, Cat | IComparable, IDisposable, IEnumerable |
Ключово
Един клас може да наследи само един родителски клас, но да имплементира колкото си иска интерфейси:
class Bird : Animal, IFlyable, IComparable<Bird> { ... }Полиморфизъм
Полиморфизъм = „един интерфейс, много форми". Един и същ метод се държи различно в зависимост от конкретния тип на обекта.
IShape[] shapes = {
new Circle { Radius = 5 },
new Rectangle { Width = 3, Height = 4 }
};
foreach (var s in shapes)
{
Console.WriteLine($"Площ: {s.Area():F2}, периметър: {s.Perimeter():F2}");
}
// Площ: 78.54, периметър: 31.42
// Площ: 12.00, периметър: 14.00Същият код работи и за Circle, и за Rectangle — програмата НЕ знае точния тип, само знае, че всеки IShape има Area и Perimeter.
Стандартни интерфейси в .NET
IComparable — сравнимост
class Student : IComparable<Student>
{
public string Name;
public double Grade;
public int CompareTo(Student other) => Grade.CompareTo(other.Grade);
}
var arr = new Student[] {
new Student { Name = "Иван", Grade = 5.50 },
new Student { Name = "Мария", Grade = 6.00 },
new Student { Name = "Петър", Grade = 4.20 }
};
Array.Sort(arr); // подреждa по Grade — благодарение на CompareToIEnumerable — за foreach
Всеки тип, който имплементира IEnumerable<T>, може да се обхожда с foreach. Това правят масивите,List<T>, и собствените ти класове, ако пожелаеш.
IDisposable — освобождаване на ресурси
Класове, които държат файлове, връзки с БД, мрежови сокети, имплементират IDisposable с метод Dispose(). Когато ги ползваш в using блок, Dispose се извиква автоматично в края.
Параметър от тип интерфейс
Силата на интерфейсите е, че пишеш кода срещу договора, не срещу конкретен клас:
static void Describe(IShape shape)
{
Console.WriteLine($"Тази форма има площ {shape.Area():F2}");
}
Describe(new Circle { Radius = 5 }); // работи
Describe(new Rectangle { Width = 3, Height = 4 }); // също работи
// А утре някой добави Triangle : IShape — Describe пак ще работи без промяна!Принцип на отвореност / затвореност
Кодът трябва да е отворен за разширение (добавяме нови типове) и затворен за модификация (без да пипаме съществуващото). Интерфейсите са основният механизъм за това.
Какво трябва да запомниш
- Интерфейс = договор (списък методи без имплементация).
- Един клас може да имплементира няколко интерфейса.
- Полиморфизъм = пишеш срещу интерфейса, работи за всеки конкретен тип.
- Стандартни:
IComparable,IEnumerable,IDisposable. - Имена с префикс
Iпо конвенция.