Что такое Interceptor (перехватчик)?

«Что такое Interceptor (перехватчик)?» — вопрос из категории Паттерны, который задают на 25% собеседований C# Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Interceptor (Перехватчик) — это паттерн проектирования, который позволяет перехватывать вызовы методов или обработку запросов для добавления сквозной функциональности (cross-cutting concerns) без модификации основного кода бизнес-логики.

Основные цели:

  • Логирование вызовов методов и их параметров.
  • Кэширование результатов дорогостоящих операций.
  • Валидация и авторизация входящих данных.
  • Управление транзакциями (открытие/закрытие, откат).
  • Измерение производительности (профилирование).

Реализация в C#: Чаще всего реализуется через:

  1. Аспектно-ориентированное программирование (AOP) с использованием библиотек (Castle DynamicProxy, PostSharp).
  2. Паттерн Декоратор для оборачивания сервисов.
  3. Фильтры в ASP.NET Core (Action Filters, Resource Filters).

Практический пример с Castle.DynamicProxy:

using Castle.DynamicProxy;

// 1. Определяем перехватчик
public class LoggingInterceptor : IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        Console.WriteLine($"[LOG] Вызов метода: {invocation.Method.Name}");
        Console.WriteLine($"[LOG] Аргументы: {string.Join(", ", invocation.Arguments)}");

        var watch = Stopwatch.StartNew();
        invocation.Proceed(); // Продолжаем выполнение оригинального метода
        watch.Stop();

        Console.WriteLine($"[LOG] Метод выполнен за {watch.ElapsedMilliseconds} мс");
        Console.WriteLine($"[LOG] Результат: {invocation.ReturnValue}");
    }
}

// 2. Создаем прокси-объект с перехватчиком
public interface IService { void ProcessData(string data); }
public class MyService : IService 
{ 
    public virtual void ProcessData(string data) { /* Логика */ } 
}

var generator = new ProxyGenerator();
IService proxy = generator.CreateClassProxy<MyService>(new LoggingInterceptor());

// 3. Вызов будет перехвачен
proxy.ProcessData("test");

Ключевые нюансы:

  • Для перехвата методов классов (не интерфейсов) методы должны быть помечены как virtual.
  • Создание прокси и перехват вносят небольшие накладные расходы на производительность.
  • Важно избегать побочных эффектов в перехватчиках, которые могут нарушить основную логику.