Прескочи до съдържанието
Редактирай

Interfaces

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) { }
}

Добри практики

  1. Именуване
// Добре - започва с I и описва поведение
public interface IDisposable
public interface IComparable
public interface IEnumerable

// Лошо - не описва поведение
public interface IData
public interface IHelper
  1. 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();
}
  1. 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;
    }
}
  1. Документация
/// <summary>
/// Дефинира контракт за работа с данни.
/// </summary>
/// <typeparam name="T">Типът на данните</typeparam>
public interface IDataAccess<T>
{
    /// <summary>
    /// Извлича всички записи.
    /// </summary>
    /// <returns>Колекция от записи</returns>
    IEnumerable<T> GetAll();
}