TGViewer
.NET Разработчик .NET Разработчик @netdeveloperdiary · 6.75K subscribers
Post #3169 1.91K
День 2642. #ЗаметкиНаПолях
Паттерн «Интерпретатор» в .NET. Расширенное использование

Начало

1. Создание правил из конфигурации
Парсим правила из JSON или БД:
public class RuleEngine
{
public IExpression BuildFromConfig(
RuleDefinition def) => def.Type switch
{
"OrderTotalGreaterThan" =>
new OrderTotalGreaterThan(
def.GetParam<decimal>("threshold")),
"CustomerIsVip" =>
new CustomerIsVip(),
"OrderContainsCategory" =>
new OrderContainsCategory(
def.GetParam<string>("category")),
"AND" =>
new AndExpression(
BuildFromConfig(def.Left!),
BuildFromConfig(def.Right!)),
"OR" =>
new OrExpression(
BuildFromConfig(def.Left!),
BuildFromConfig(def.Right!)),
"NOT" =>
new NotExpression(BuildFromConfig(def.Left!)),
_ => throw new InvalidOperationException(
$"Неизвестный тип: {def.Type}")
};
}


Определение правила в JSON:
{
"type": "AND",
"left": { "type": "CustomerIsVip" },
"right": { "type": "OrderTotalGreaterThan", "params": { "threshold": 200 } }
}

Теперь отдел маркетинга может определять правила в UI панели управления. RuleEngine анализирует и оценивает их без изменения кода.

2. Парсинг выражений для вычисляемых полей
Аналогично можно создавать математические выражения:
public interface IMathExpression
{
decimal Evaluate(Dictionary<string, decimal> variables);
}

public class NumberLiteral(decimal value)
: IMathExpression
{
public decimal Evaluate(Dictionary<string, decimal> variables)
=> value;
}

public class Variable(string name)
: IMathExpression
{
public decimal Evaluate(Dictionary<string, decimal> variables)
=> variables[name];
}

public class Multiply(IMathExpression left, IMathExpression right)
: IMathExpression
{
public decimal Evaluate(Dictionary<string, decimal> variables)
=> left.Evaluate(variables) * right.Evaluate(variables);
}

// Выражение: price * quantity * (1 - discount)
var totalExpr = new Multiply(
new Multiply(new Variable("price"), new Variable("quantity")),
new Subtract(new NumberLiteral(1), new Variable("discountRate")));

var vars = new Dictionary<string, decimal>
{
["price"] = 29.99m, ["quantity"] = 3, ["discount"] = 0.10m
};

var total = totalExpr.Evaluate(vars); // 80.973


Когда не использовать
1. Для сложных правил. Если нужны циклы, функции или сложный синтаксис, используйте подходящий генератор парсеров (ANTLR) или существующий скриптовый движок (Roslyn, Lua). Паттерн «Интерпретатор» плохо масштабируется для сложных языков.

2. Важна производительность. Каждый вызов Interpret() проходит по дереву выражений. Для часто используемых путей с миллионами вычислений скомпилированные выражения (Expression<T>.Compile()) на порядки быстрее.

3. Правила редко меняются. Если правила стабильны и меняются раз в год, затраты на создание интерпретатора не оправданы. Просто пишите условия напрямую.

«Интерпретатор» избыточен?
Для 3-4 фиксированных условий — да. Просто используйте if-else. Паттерн особенно эффективен, когда у вас более 20 правил, которые регулярно меняются и позволяют создавать комбинации без перекомпиляции кода.

Альтернативы
Для оценки во время выполнения деревья выражений C# Expression<T> компилируются в IL. Для простой оценки правил может подойти словарь делегатов или паттерн «Стратегия».

Источник:
https://thecodeman.net/posts/interpreter-pattern-in-dotnet
  • 👍 3
More from @netdeveloperdiary
  1. Sep 27, 2026День 2797. #ЗаметкиНаПолях #AI Рабочий процесс с Copilot для .NET. Окончание Начало Продол…
  2. Sep 26, 2026День 2796. #ЗаметкиНаПолях #AI Рабочий процесс с Copilot для .NET. Продолжение Начало Три…
  3. Sep 25, 2026День 2795. #ЗаметкиНаПолях #AI Рабочий процесс с Copilot для .NET. Начало Проблема с позиц…
  4. Sep 24, 2026День 2794. #Оффтоп #Здоровье Сегодня будет необычный пост. Завтра в Москве стартует конфер…
  5. Sep 23, 2026День 2793. #ЗаметкиНаПолях #SQL 10 Редких Возможностей SQL, Которые Стоит Знать Каждому. Ч…
  6. Sep 22, 2026День 2792. #ЗаметкиНаПолях #SQL 10 Редких Возможностей SQL, Которые Стоит Знать Каждому. Ч…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →