Init-only, required e target-typed new
Resumo
initpermite definir uma propriedade só na criação;requiredobriga o chamador a informá-la; target-typednew()remove a repetição do nome do tipo. Juntos, tornam a inicialização segura e concisa.
1. Objetivos de Aprendizagem#
- Usar propriedades
initpara imutabilidade após a criação. - Obrigar propriedades essenciais com
required. - Simplificar instâncias com target-typed
new().
2. Pré-requisitos#
- Records e imutabilidade (tópico 6.1).
3. Conceito#
init: o setter só pode ser usado durante a inicialização (construtor ou object initializer). Depois, a propriedade é somente-leitura.required: o compilador exige que a propriedade seja definida na criação, sem precisar de um construtor completo.- Target-typed
new(): quando o tipo já é conhecido pelo contexto (variável, parâmetro), você escreve sónew().
O porquê: garantir que objetos nasçam completos e imutáveis, com menos código repetitivo.
4. Mão na Massa#
4.1. Setup#
dotnet new console -n Catalog.Init
cd Catalog.Init
4.2. Implementação Passo a Passo#
init+required:
public class Produto
{
public required string Nome { get; init; }
public required decimal Preco { get; init; }
public string? Descricao { get; init; } // opcional
}
var p = new Produto { Nome = "Teclado", Preco = 120m };
// p.Nome = "x"; // ERRO: init-only, não pode alterar depois
Omitir Nome ou Preco acima gera erro de compilação (por causa de required).
- Target-typed
new():
Produto criar() => new() { Nome = "Mouse", Preco = 90m };
List<int> numeros = new() { 1, 2, 3 }; // tipo inferido do lado esquerdo
4.3. Executando#
dotnet run
5. Exemplo Completo#
public class CriarProdutoRequest
{
public required string Nome { get; init; }
public required decimal Preco { get; init; }
}
CriarProdutoRequest req = new() { Nome = "Monitor", Preco = 1200m };
O DTO é imutável, obriga os campos essenciais e é criado sem repetir o nome do tipo.
6. Boas Práticas e Armadilhas#
| Faça | Evite |
|---|---|
Marcar campos obrigatórios como required | Deixar objetos nascerem incompletos e validar tarde |
Usar init para imutabilidade pós-criação | set público quando o valor não deveria mudar |
Target-typed new() quando o tipo é óbvio | Abusar de new() onde o tipo fica ilegível |
Atenção
requiredé verificado em compilação ao usar object initializer. Frameworks que criam objetos por reflexão (serializadores) têm suporte específico — configure-os quando necessário.
7. Segurança e Produção#
required+initgarantem invariantes na criação, reduzindo estados inválidos que só apareceriam em runtime.
8. Exercícios#
- Fácil: crie um DTO com duas propriedades
required. - Médio: tente criar o objeto sem uma delas e observe o erro do compilador.
- Desafio: combine
required,inite target-typednew()num pequeno modelo de pedido.
9. Resumo#
init dá imutabilidade após a criação; required obriga campos essenciais; target-typed new() remove repetição. Juntos, produzem inicialização segura e concisa.
10. Próximos Passos#
Encerramos C# moderno. A seguir, estruturas de dados: coleções e generics.
11. Referências#
- Microsoft Learn — init
- Microsoft Learn — Membros required
- Microsoft Learn — Expressões new com tipo de destino