
Bruno SantosO C# adotou cadência anual de releases a partir do .NET 6, lançado em novembro de 2021. Em cinco...
O C# adotou cadência anual de releases a partir do .NET 6, lançado em novembro de 2021. Em cinco anos, foram cinco versões: C# 10, 11, 12, 13 e 14. Todas mantiveram compatibilidade retroativa. Para times .NET, isso significa que o compilador entregou features novas todo novembro, mas muitos projetos ficam em versões antigas por omissão de configuração. Mapear o que cada versão trouxe é o primeiro passo para entender o que está disponível e o que ainda pode ser adotado.
O C# 10 (nov. 2021) foi sobre redução de cerimônia. File-scoped namespace declarations eliminaram o bloco aninhado que todo arquivo carregava. Global using directives permitiram centralizar imports comuns no nível do projeto, em vez de repetir os mesmos usings em cada arquivo. Record structs estenderam para structs a síntese de membros e as with expressions que record classes já tinham.
Lambdas ganharam tipo natural (o compilador infere o tipo de delegate), suporte a retorno explícito quando necessário e a possibilidade de receber atributos. Interpolated string handlers abriram espaço para implementações de interpolação customizadas, o que o runtime do .NET 6 usou para eliminação de alocações em logging. CallerArgumentExpression permitiu capturar a expressão de um argumento como string no compilador, útil para mensagens de assertion e diagnóstico.
O C# 11 (nov. 2022) teve generic math como tema central. Através de membros static abstract em interfaces, passou a ser possível escrever algoritmos numéricos uma vez e reutilizá-los para qualquer tipo que implemente a interface. A própria biblioteca base do .NET 7 usou essa feature para unificar as APIs numéricas.
Required members tornaram obrigatória a inicialização de propriedades marcadas, melhorando a segurança de tipos em construção. Auto-default structs simplificaram a semântica de valor padrão. ref fields com scoped ref trouxeram controle fino sobre tempo de vida de referências. Raw string literals eliminaram a necessidade de escapes em strings multiline. UTF-8 string literals permitem literais codificadas diretamente como UTF-8 sem conversão em runtime. File-local types tornam um tipo privado ao arquivo de compilação, útil para source generators. List patterns expandiram o pattern matching para decomposição de coleções. Generic attributes, que estavam em preview no C# 10, foram finalizados.
O C# 12 (nov. 2023) generalizou primary constructors para qualquer class ou struct, não apenas para records. Com isso, os parâmetros do construtor ficam acessíveis em todo o corpo do tipo, eliminando a necessidade de declarar campos de backing explícitos apenas para armazenar valores recebidos na construção.
Collection expressions trouxeram uma sintaxe unificada para criação de coleções, com o spread operator (..) para expandir coleções existentes dentro de outra coleção. Inline arrays permitem declarar um array de tamanho fixo embutido em uma struct, sem heap allocation, útil para buffers de alta performance. Lambdas passaram a aceitar valores padrão em parâmetros. ref readonly parameters adicionaram clareza a APIs que precisavam de parâmetros por referência somente de leitura. Using aliases passaram a aceitar qualquer tipo, não apenas named types.
O C# 13 (nov. 2024) expandiu o modificador params para aceitar qualquer tipo de coleção reconhecido pelo compilador, não apenas arrays. Isso simplifica APIs que precisam aceitar Span, ReadOnlySpan ou interfaces de coleção sem exigir sobrecarga de método.
O tipo System.Threading.Lock recebeu semântica dedicada no compilador. Quando um lock statement tem como alvo esse tipo, o compilador gera código usando o método EnterScope(), que retorna um ref struct com suporte ao padrão Dispose() para sair do escopo exclusivo de forma determinística. ref struct passou a poder implementar interfaces e ser usado como argumento de tipo em genéricos. Partial properties e indexers foram adicionados ao suporte de membros parciais. Overload resolution priority permite que autores de bibliotecas designem uma sobrecarga como preferida pelo compilador, útil para guiar consumidores para implementações mais eficientes. ref locals e contextos unsafe passaram a ser permitidos em métodos async e iterators.
O C# 14 (nov. 2025) entregou extension members, que generalizam extension methods para incluir propriedades, operadores e outros membros de instância. A ideia de extensão, até então limitada a métodos, passa a funcionar para qualquer tipo de membro.
O keyword field resolve um problema concreto: declarar uma propriedade com lógica custom sem precisar criar um campo de backing explícito. Em vez de declarar um campo privado separadamente, o corpo da propriedade pode referenciar field diretamente. Null-conditional assignment simplifica atribuições condicionais em null. User-defined compound assignment operators permitem que tipos definam o comportamento de operadores como +=. nameof passou a aceitar generics não-bound, o que é útil para mensagens de diagnóstico e reflexão. Partial events e construtores completam o suporte a membros parciais em tipos parciais.
Cinco versões em cinco anos seguiram um padrão coerente: cada release fechou um pouco mais a distância entre o que o programador precisa escrever e o que o compilador pode inferir, sem mudar o modelo de execução subjacente. As features não são independentes entre si: generic math em C# 11 preparou o terreno para coleções genéricas mais expressivas em C# 12 e 13; extension members em C# 14 completam o que extension methods iniciaram no C# 3.
O primeiro passo prático é verificar qual versão de linguagem está declarada no csproj. Muitos projetos ficam em versões antigas porque a versão padrão acompanha o target framework, e atualizar o framework tem custo de teste que atualizar só a versão de linguagem não tem. O compilador indica com avisos as oportunidades de simplificação disponíveis. Como o time trabalha e o que está em produção determinam o que faz sentido adotar. Devemos analisar cada feature no contexto do projeto antes de fazer a adoção em larga escala.
Fonte: The history of C#