Introdução: dois lados da mesma moeda
\n\nImagine que você está construindo uma casa. Você pode pegar blocos prontos (classes, objetos, herança) e montar uma estrutura complexa com eles — isso é programação orientada a objetos (POO). Ou pode pensar como um matemático: "eu pego os dados, aplico uma função pura a eles e obtenho um novo resultado, sem mudar nada" — isso é programação funcional.
\n\nEm C#, ambos os paradigmas coexistem de forma surpreendente. E se você escreve nesta linguagem, mais cedo ou mais tarde se perguntará: "E se eu estiver fazendo isso errado? Será que deveria usar mais LINQ e menos classes?"
\n\nNeste artigo, não vamos discutir o que é melhor. Vamos entender como a abordagem funcional difere da POO em C#, quando cada uma realmente ajuda e quando atrapalha. E sim, terá muito código. Vamos nessa!
\n\n1. POO em C#: o clássico que funciona
\n\nProgramação orientada a objetos é sobre estado e comportamento. Você tem uma classe que armazena dados (campos, propriedades) e métodos que alteram esses dados.
Exemplo: um aplicativo para gerenciar pedidos em uma loja online.
\n\npublic class Order\n{\n public int Id { get; set; }\n public List<string> Items { get; private set; }\n public decimal TotalPrice { get; private set; }\n\n public Order(int id)\n {\n Id = id;\n Items = new List<string>();\n TotalPrice = 0;\n }\n\n public void AddItem(string itemName, decimal price)\n {\n Items.Add(itemName);\n TotalPrice += price;\n }\n\n public void ApplyDiscount(decimal percent)\n {\n TotalPrice -= TotalPrice * (percent / 100);\n }\n}\n\nO que vemos? Encapsulamento: TotalPrice não pode ser alterado diretamente — apenas através de métodos. Estado do objeto muda com o tempo: adicionamos itens, aplicamos descontos. Isso é POO pura.
Vantagens da POO em C#
\n- \n
- Modelo compreensível do mundo real: Pedido, Cliente, Produto — tudo como na vida real. \n
- Reutilização através de herança e interfaces. \n
- Gerenciamento de complexidade ao dividir em pequenos objetos. \n
Desvantagens da POO
\n- \n
- Efeitos colaterais: um método pode alterar o estado, e você facilmente perde o controle. \n
- Dificuldade de teste: é necessário criar objetos, simular dependências. \n
- Redundância: às vezes é mais simples escrever uma função do que criar uma classe inteira. \n
2. Abordagem funcional em C#: LINQ e além
\n\nProgramação funcional é sobre funções puras (sem efeitos colaterais) e imutabilidade de dados. Em C#, isso é especialmente visível em LINQ, expressões lambda e trabalho com coleções.
\n\nVamos resolver a mesma tarefa — gerenciar um pedido — mas de forma funcional.
\n\n// Registro imutável (record)\npublic record Order(int Id, List<string> Items, decimal TotalPrice);\n\npublic static class OrderFunctions\n{\n public static Order AddItem(Order order, string item, decimal price)\n {\n var newItems = order.Items.Append(item).ToList();\n return order with { Items = newItems, TotalPrice = order.TotalPrice + price };\n }\n\n public static Order ApplyDiscount(Order order, decimal percent)\n {\n return order with { TotalPrice = order.TotalPrice * (1 - percent / 100) };\n }\n}\n\n// Uso\nvar order = new Order(1, new List<string>(), 0);\norder = OrderFunctions.AddItem(order, "Notebook", 50000);\norder = OrderFunctions.ApplyDiscount(order, 10);\n\nPercebeu? Não alteramos o objeto original. Cada vez, uma nova instância é criada usando with. Isso elimina alterações acidentais.
E