Функциональное Программирование в C#. Окончание
Части 1, 2, 3-4
5. Неизменяемость
Неизменяемые объекты не могут быть изменены после создания. Вместо этого создаются новые экземпляры для каждого изменения. Это простое ограничение устраняет целые категории ошибок: состояния гонки, случайные модификации и несогласованное состояние. Вот пример изменяемого типа:
public class Order
{
public List<OrderItem> Items { get; set; }
public decimal Total { get; set; }
public OrderStatus Status { get; set; }
public void AddItem(OrderItem item)
{
Items.Add(item);
Total += item.Price;
// Проблемы потокобезопасности
// Можно изменять отправленные заказы
// Total и Items могут не совпадать
}
}
Сделаем тип неизменяемым:
public record Order
{
public ImmutableList<OrderItem>
Items { get; init; }
public OrderStatus
Status { get; init; }
public decimal Total =>
Items.Sum(x => x.Price);
public Order AddItem(OrderItem item)
{
if (Status != OrderStatus.Created)
throw new InvalidOperationException(
"Нельзя изменять отправленный заказ");
return this with
{
Items = Items.Add(item)
};
}
}
Неизменяемая версия:
- по умолчанию потокобезопасна,
- делает недопустимые состояния невозможными,
- держит данные и вычисления согласованными,
- делает изменения явными и отслеживаемыми.
Итого
Функциональное программирование — не просто написание «более чистого» кода. Эти паттерны фундаментально меняют то, как вы управляете сложностью:
1. Переносите ошибки на время компиляции, выявляйте проблемы до запуска кода.
2. Делайте недопустимые состояния невозможными, не полагайтесь на документацию или соглашения.
3. Делайте счастливый путь очевидным. Объект должно быть легко использовать правильно и сложно использовать неправильно.
Вы можете постепенно внедрять эти шаблоны. Начните с одного класса, одного модуля, одной функции. Цель не в том, чтобы написать чисто функциональный код. Цель в том, чтобы писать код, который будет более безопасным, предсказуемым и простым в обслуживании.
Источник: https://www.milanjovanovic.tech/blog/functional-programming-in-csharp-the-practical-parts