Interfaces (Интерфейси)
Интерфейсите са абстрактни дефиниции на методи и свойства, които класовете трябва да имплементират. Те дефинират контракт, който класовете трябва да спазват.
Основен синтаксис
public interface IAnimal
{
string Name { get; set; }
void MakeSound();
bool CanFly { get; }
}
public class Dog : IAnimal
{
public string Name { get; set; }
public void MakeSound()
{
Console.WriteLine("Woof!");
}
public bool CanFly => false;
}
Множествено наследяване
public interface ILogger
{
void Log(string message);
}
public interface IFormatter
{
string Format(string input);
}
public class ConsoleLogger : ILogger, IFormatter
{
public void Log(string message)
{
Console.WriteLine(Format(message));
}
public string Format(string input)
{
return $"[{DateTime.Now}] {input}";
}
}
Default имплементация (C# 8.0+)
public interface IRepository<T>
{
T GetById(int id);
IEnumerable<T> GetAll();
// Default имплементация
bool Exists(int id)
{
return GetById(id) != null;
}
int Count => GetAll().Count();
}
Експлицитна имплементация
public interface IA
{
void Method();
}
public interface IB
{
void Method();
}
public class MyClass : IA, IB
{
// Експлицитна имплементация за IA
void IA.Method()
{
Console.WriteLine("IA.Method");
}
// Експлицитна имплементация за IB
void IB.Method()
{
Console.WriteLine("IB.Method");
}
}
Generic интерфейси
public interface IRepository<T> where T : class
{
T GetById(int id);
void Add(T entity);
void Update(T entity);
void Delete(T entity);
IEnumerable<T> Find(Expression<Func<T, bool>> predicate);
}
public class SqlRepository<T> : IRepository<T> where T : class
{
private readonly DbContext context;
private readonly DbSet<T> dbSet;
public SqlRepository(DbContext context)
{
this.context = context;
this.dbSet = context.Set<T>();
}
public T GetById(int id) => dbSet.Find(id);
public void Add(T entity) => dbSet.Add(entity);
public void Update(T entity) => context.Entry(entity).State = EntityState.Modified;
public void Delete(T entity) => dbSet.Remove(entity);
public IEnumerable<T> Find(Expression<Func<T, bool>> predicate)
=> dbSet.Where(predicate);
}
Интерфейси като параметри
public interface IPaymentProcessor
{
bool ProcessPayment(decimal amount);
}
public class PaymentService
{
private readonly IPaymentProcessor processor;
public PaymentService(IPaymentProcessor processor)
{
this.processor = processor;
}
public bool MakePayment(decimal amount)
{
// Логиката е независима от конкретната имплементация
return processor.ProcessPayment(amount);
}
}
Covariance и Contravariance
// Covariance с out
public interface IProducer<out T>
{
T Produce();
}
// Contravariance с in
public interface IConsumer<in T>
{
void Consume(T item);
}
public class Producer : IProducer<Animal>
{
public Animal Produce() => new Dog();
}
public class Consumer : IConsumer<Dog>
{
public void Consume(Dog dog) { }
}
Добри практики
- Именуване
// Добре - започва с I и описва поведение
public interface IDisposable
public interface IComparable
public interface IEnumerable
// Лошо - не описва поведение
public interface IData
public interface IHelper
- Interface Segregation Principle
// Лошо - твърде много отговорности
public interface IRepository
{
void Save();
void Delete();
void SendEmail();
void GenerateReport();
}
// Добре - разделени отговорности
public interface IRepository
{
void Save();
void Delete();
}
public interface IMessageSender
{
void SendEmail();
}
public interface IReportGenerator
{
void GenerateReport();
}
- Dependency Inversion
// Добре - зависи от абстракция
public class OrderProcessor
{
private readonly ILogger logger;
private readonly IPaymentProcessor payment;
public OrderProcessor(ILogger logger, IPaymentProcessor payment)
{
this.logger = logger;
this.payment = payment;
}
}
- Документация
/// <summary>
/// Дефинира контракт за работа с данни.
/// </summary>
/// <typeparam name="T">Типът на данните</typeparam>
public interface IDataAccess<T>
{
/// <summary>
/// Извлича всички записи.
/// </summary>
/// <returns>Колекция от записи</returns>
IEnumerable<T> GetAll();
}