Records
Records em C# representam um recurso introduzido a partir do C# 9.0 que facilita a criação de tipos imutáveis, fortemente focados em representar dados. Ao contrário das classes tradicionais, que priorizam identidade e comportamento, os records são projetados para capturar o estado de uma entidade de maneira concisa, priorizando igualdade estrutural e semântica. Isso significa que dois objetos do tipo record com os mesmos valores em suas propriedades são considerados iguais, diferentemente do comportamento padrão de classes.
O uso de records é especialmente útil em cenários que envolvem transferência de dados, como DTOs (Data Transfer Objects), padrões de mensagens em arquiteturas orientadas a eventos e na implementação de algoritmos onde a integridade do estado é fundamental. No contexto de arquitetura de software, records contribuem para um design mais seguro, reduzindo riscos de mutação inadvertida e facilitando práticas como programação funcional dentro do ecossistema C#.
Neste tutorial, você aprenderá desde a sintaxe básica dos records, passando por seu uso prático em estruturas de dados e algoritmos, até a aplicação em princípios de orientação a objetos. Também exploraremos boas práticas, armadilhas comuns a evitar e como records se integram em arquiteturas modernas baseadas em imutabilidade e mensagens.
Exemplo Básico
textusing System;
public record Produto(string Nome, decimal Preco);
public class Program
{
public static void Main()
{
var produto1 = new Produto("Notebook", 4500.00m);
var produto2 = new Produto("Notebook", 4500.00m);
Console.WriteLine(produto1);
Console.WriteLine($"Os produtos são iguais? {produto1 == produto2}");
}
}
No exemplo acima, criamos um record chamado Produto, que possui duas propriedades: Nome e Preco. A sintaxe de record com construtor posicional permite definir propriedades de maneira concisa e imutável. Essa abordagem elimina a necessidade de boilerplate code, como construtores explícitos, getters e métodos Equals/GetHashCode.
A linha var produto1 = new Produto("Notebook", 4500.00m); demonstra a criação de uma instância imutável. Alterações de valores só podem ser realizadas através da expressão with, o que reforça a imutabilidade. Ao criar produto2 com os mesmos valores, a comparação produto1 == produto2 retorna verdadeiro, pois records implementam igualdade estrutural ao invés de identidade de referência.
Outro ponto importante é a sobrescrita automática do método ToString(). Ao imprimir produto1, o console mostra "Produto { Nome = Notebook, Preco = 4500.00 }", o que fornece uma representação clara e útil para debug.
Esse exemplo ilustra a essência de records: redução de código repetitivo, maior clareza semântica e aderência às boas práticas de imutabilidade. Em projetos reais, esse comportamento é crucial em cenários de DTOs, microserviços e camadas de domínio em arquiteturas DDD (Domain-Driven Design), onde a igualdade semântica é preferível à igualdade de referência.
Exemplo Prático
textusing System;
using System.Collections.Generic;
public record Cliente(string Nome, string Email);
public record Pedido(int Id, Cliente Cliente, decimal ValorTotal);
public class Program
{
public static void Main()
{
var cliente = new Cliente("Maria Silva", "[[email protected]](mailto:[email protected])");
var pedido1 = new Pedido(1, cliente, 1500.00m);
var pedido2 = pedido1 with { ValorTotal = 2000.00m };
List<Pedido> pedidos = new() { pedido1, pedido2 };
foreach (var pedido in pedidos)
{
Console.WriteLine(pedido);
}
Console.WriteLine($"Pedidos iguais? {pedido1 == pedido2}");
}
}
C# best practices e armadilhas comuns relacionadas a records envolvem principalmente a correta aplicação de imutabilidade e a atenção à performance. Sempre que possível, utilize a sintaxe de construtor posicional para reduzir redundância e garantir clareza. Em casos mais complexos, pode-se expandir o record para incluir propriedades adicionais, mantendo a lógica de igualdade estrutural.
Uma prática recomendada é empregar records para representar entidades que não exigem identidade única ou mutabilidade. Por exemplo, DTOs em APIs, eventos em sistemas orientados a mensagens e modelos em sistemas baseados em CQRS (Command Query Responsibility Segregation). Nesses cenários, a imutabilidade garante consistência e reduz bugs relacionados a mutações inesperadas.
As armadilhas mais comuns incluem o uso incorreto de records como classes mutáveis, o que elimina os benefícios de imutabilidade, e o desconhecimento da diferença entre igualdade de referência e estrutural. Outro erro é não considerar o impacto de records em coleções grandes: o cálculo de igualdade estrutural pode gerar sobrecarga em algoritmos intensivos, devendo-se avaliar trade-offs de performance.
Na depuração, aproveite o método ToString() gerado automaticamente, que facilita rastrear valores internos. Para otimizar performance, evite aninhar records de maneira profunda em cenários de alta escala. Por fim, considere também aspectos de segurança, como não expor dados sensíveis em ToString(), que pode ser logado inadvertidamente.
📊 Tabela de Referência
C# Element/Concept | Description | Usage Example |
---|---|---|
Record Posicional | Define propriedades de forma concisa e imutável | public record Produto(string Nome, decimal Preco); |
Operador with | Permite criar cópias modificadas mantendo imutabilidade | var novoPedido = pedido with { ValorTotal = 3000.00m }; |
Igualdade Estrutural | Compara valores das propriedades, não referências | produto1 == produto2 |
ToString() Automático | Gera representação legível da instância | Console.WriteLine(produto1); |
Uso em DTOs | Ideal para transferir dados entre camadas | public record ClienteDTO(string Nome, string Email); |
Em resumo, records em C# oferecem uma maneira elegante e eficiente de modelar dados imutáveis, reduzindo código repetitivo e fortalecendo práticas de design baseadas em igualdade estrutural. A principal lição é compreender que records não são substitutos de classes tradicionais, mas sim complementos poderosos em cenários onde integridade de dados e simplicidade de representação são prioritários.
Esse recurso conecta-se a tópicos mais amplos do desenvolvimento em C#, como programação funcional, padrões arquiteturais baseados em mensagens e práticas de DDD. A utilização correta de records ajuda a criar sistemas mais previsíveis, resilientes e fáceis de manter.
Como próximos passos, recomenda-se estudar tópicos como imutabilidade avançada, padrões de design (CQRS, Event Sourcing) e o uso de records em conjunto com LINQ para manipulação de coleções. Para aplicação prática, implemente records em DTOs de APIs REST ou em eventos de microserviços.
Para aprofundar-se ainda mais, explore a documentação oficial do C#, estude projetos open-source que aplicam records em larga escala e pratique criando modelos de domínio baseados em records em sistemas complexos.
🧠 Teste Seu Conhecimento
Test Your Knowledge
Test your understanding of this topic with practical questions.
📝 Instruções
- Leia cada pergunta cuidadosamente
- Selecione a melhor resposta para cada pergunta
- Você pode refazer o quiz quantas vezes quiser
- Seu progresso será mostrado no topo