Como testar o .NET 8 e C# 12 hoje mesmo!

O C# 12 preview chegou junto com o .NET 8 Preview 3, lançado em abril de 2023, e trouxe as primeiras novidades da próxima versão da linguagem. Neste artigo, você vai instalar o SDK, conferir a versão, habilitar o Language Preview no .csproj e compilar um exemplo com os recursos novos.

Antes de começar, vale um aviso: tudo aqui é pré-visualização. O .NET 8 tinha lançamento previsto para novembro de 2023, então muita coisa ainda podia mudar até a versão final.

O que é o C# 12 preview

O C# 12 preview é o conjunto de recursos da versão 12 da linguagem que a Microsoft libera antes do lançamento oficial. A ideia é permitir que a comunidade teste, aponte problemas e dê feedback enquanto o time ainda pode ajustar o design.

No anúncio publicado no blog do .NET em 11 de abril de 2023, a equipe apresentou três recursos disponíveis com o .NET 8 Preview 3 e o Visual Studio 17.6 preview. São eles:

  • Construtores primários para qualquer classe ou struct, e não apenas para records.
  • Aliases com using para qualquer tipo, incluindo tuplas, tipos anuláveis e genéricos.
  • Valores padrão para parâmetros de expressões lambda.

Você encontra os detalhes de cada recurso na página oficial What's new in C# 12, que a Microsoft mantém atualizada.

Como instalar o .NET 8

Você pode baixar o .NET 8 no site oficial da Microsoft, na página de downloads da versão 8.0. Lá estão os instaladores do SDK para Windows, macOS e Linux.

🔗 https://dotnet.microsoft.com/en-us/download/dotnet/8.0

Para testar o C# 12 preview, você precisa instalar o .NET 8 Preview 3 ou uma versão superior. Versões anteriores do SDK simplesmente não conhecem a nova sintaxe.

Além disso, a instalação do preview convive com as versões estáveis. Assim, seus projetos em .NET 6 ou .NET 7 continuam funcionando normalmente na mesma máquina.

Por que a versão do C# acompanha o .NET

O C# é uma linguagem gerenciada, e no caso quem gerencia é o .NET. Por isso, a versão da linguagem acompanha a versão do framework.

Desta forma, para usar o C# 12 você precisa do .NET 8, e para testar o C# 12 preview precisa de um SDK preview desse framework. Seguindo a mesma lógica, para usar o C# 11 precisa do .NET 7, para o C# 10 precisa do .NET 6, e assim por diante. A documentação oficial resume essa relação em uma tabela de versões padrão por framework de destino:

Framework de destino Versão padrão do C#
.NET 8 C# 12
.NET 7 C# 11
.NET 6 C# 10
.NET 5 C# 9
.NET Core 3.x C# 8
.NET Framework C# 7.3

O compilador escolhe essa versão automaticamente com base no TargetFramework do projeto, e é por isso que o C# 12 preview exige atenção extra na configuração. Com isso, você usa sempre a versão mais recente compatível, sem depender de recursos que o runtime não oferece.

Language Preview e o C# 12 preview

É importante salientar que o C# 12 preview estava disponível no .NET 8 Preview 3 apenas como pré-visualização. Ou seja, os recursos ainda podiam mudar de nome, de sintaxe ou até sair da versão final.

Já vimos isso acontecer no passado. O operador !!, que fazia checagem automática de parâmetros nulos, apareceu em previews do C# 11 e acabou removido antes do lançamento, então não se apegue demais aos recursos novos até a versão estável.

O Language Preview é uma configuração do arquivo .csproj que diz qual versão do C# o compilador vai aceitar no projeto. Na prática, ela fica na propriedade LangVersion.

Você pode usar essa propriedade tanto para aumentar quanto para diminuir a versão da linguagem, sempre respeitando o framework em uso. Por exemplo, se você está no .NET 6, pode usar o C# 10 ou inferior, mas nunca uma versão superior com suporte oficial.

Por fim, é importante entender que o C# é distribuído em versões próprias. Ter o .NET 8 como TargetFramework não significa, por si só, que você está usando os recursos mais novos da linguagem.

Verificando a versão instalada

Com o .NET instalado, feche seus terminais e abra novamente, para que o PATH seja recarregado. Em seguida, execute o comando abaixo para verificar a versão do SDK:

dotnet --version
# 8.0.100-preview.3.23178.7

O número 8.0.100-preview.3 confirma que o SDK do Preview 3, necessário para o C# 12 preview, está ativo. Se aparecer outra versão, liste todos os SDKs instalados para conferir:

dotnet --list-sdks

Além disso, no cenário testado neste artigo, o projeto criado com o .NET 8 Preview 3 continuava usando o C# 11 como linguagem padrão. Por isso, foi preciso habilitar o Language Preview no arquivo .csproj para liberar a sintaxe do C# 12 preview.

Descobrindo a versão da linguagem em uso

Existe um truque simples para saber qual versão do C# o compilador está usando. Basta colocar a diretiva #error version em qualquer arquivo do projeto:

#error version

Ao compilar, o compilador gera o erro CS8304 com a versão do compilador e a versão da linguagem selecionada. Depois de conferir, remova a linha para o build voltar a funcionar.

Criando um projeto para testar o C# 12 preview

O jeito mais seguro de experimentar o C# 12 preview é criar um projeto de console separado. Assim, você testa a sintaxe nova sem tocar em nenhum código de produção.

dotnet new console -o CSharp12Preview
cd CSharp12Preview

O template já cria o arquivo CSharp12Preview.csproj e um Program.cs com top-level statements. Em seguida, basta ajustar o projeto conforme a próxima seção.

Se você trabalha em equipe, também vale fixar a versão do SDK. Para isso, crie um arquivo global.json na raiz do repositório:

{
  "sdk": {
    "version": "8.0.100-preview.3.23178.7",
    "allowPrerelease": true
  }
}

Com esse arquivo, o comando dotnet usa exatamente o SDK informado naquela pasta. Dessa forma, todos rodam o mesmo compilador e evitam resultados diferentes entre máquinas.

Habilitando o C# 12 preview no csproj

A ativação acontece pela propriedade LangVersion, que deve receber o valor preview. Veja como fica o arquivo do projeto:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <!-- Garante que o projeto está no .NET 8 -->
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <!-- Adicione esta linha para liberar o C# 12 preview -->
    <LangVersion>preview</LangVersion>
  </PropertyGroup>

</Project>

Repare em duas linhas. Primeiro, o TargetFramework precisa estar em net8.0, porque a versão preview da linguagem depende do framework correspondente.

Depois, a linha <LangVersion>preview</LangVersion> diz ao compilador para aceitar toda sintaxe válida da versão preview mais recente. Segundo a documentação, esse é exatamente o significado do valor preview.

Outros valores de LangVersion

A propriedade aceita outros valores além de preview. Os principais são:

  • preview: aceita toda sintaxe da versão preview mais recente.
  • latest: aceita a sintaxe da última versão lançada do compilador, incluindo versões menores.
  • latestMajor ou default: aceita a última versão principal lançada.
  • Um número, como 11 ou 12: aceita apenas a sintaxe daquela versão ou inferior.

A Microsoft recomenda não usar latest em projetos reais. Como o valor depende do compilador instalado, o mesmo projeto pode compilar em uma máquina e falhar em outra.

Testando os recursos do C# 12 preview

Com o projeto configurado, você já pode escrever código com os três recursos anunciados. O exemplo abaixo reúne todos em um único Program.cs:

// Alias para uma tupla (using alias para qualquer tipo)
using Measurement = (string Units, int Distance);

// Lambda com valor padrão no parâmetro
var addWithDefault = (int addTo = 2) => addTo + 1;
Console.WriteLine(addWithDefault());  // 3
Console.WriteLine(addWithDefault(5)); // 6

Measurement trip = ("km", 120);
Console.WriteLine($"{trip.Distance} {trip.Units}");

var student = new Student(1, "  Ana  ", [9.5m, 8.0m]);
Console.WriteLine($"{student.Id} - {student.Name}");

// Construtor primário em uma classe comum
public class Student(int id, string name, IEnumerable<decimal> grades)
{
    public int Id => id;
    public string Name { get; set; } = name.Trim();
    public decimal Average => grades.Average();
}

O construtor primário declara os parâmetros direto na classe, e eles ficam disponíveis em todo o corpo dela. Assim, você evita escrever um construtor só para copiar valores para campos.

Já o alias Measurement dá um nome curto para uma tupla, algo que antes o using não permitia. Por sua vez, a lambda addWithDefault funciona como um método com parâmetro opcional.

Note que a criação do Student usa uma expressão de coleção com colchetes, outro recurso do C# 12. Se o seu preview ainda não reconhecer essa sintaxe, troque por new[] { 9.5m, 8.0m }.

Detalhes dos construtores primários

Nos records, os parâmetros do construtor primário viram propriedades públicas automaticamente. Em classes e structs comuns, porém, o comportamento é diferente.

Neste recurso do C# 12 preview, os parâmetros funcionam como variáveis disponíveis no corpo da classe, e não como propriedades. Por isso, no exemplo, foi preciso declarar Id e Name de forma explícita para expor os valores.

Além disso, qualquer outro construtor da classe precisa chamar o construtor primário com this(...). Essa regra garante que os parâmetros sempre tenham valor.

Aliases e lambdas com valor padrão

Antes do C# 12 preview, a diretiva using só criava aliases para tipos com nome, como classes e namespaces. Agora ela também aceita tuplas, arrays, tipos anuláveis como int? e tipos genéricos fechados.

Na prática, isso deixa o código mais expressivo. Por exemplo, um alias using DatabaseInt = int?; comunica a intenção melhor do que repetir int? em vários pontos.

Já as lambdas ganharam valores padrão nos parâmetros, com a mesma sintaxe usada em métodos. Com isso, quem chama a lambda pode omitir o argumento, e o valor padrão entra no lugar.

O balta.io também tem um artigo dedicado aos construtores primários no C# 12, com mais exemplos e cuidados de uso.

Compilando e executando o exemplo

Com o código pronto, rode o build pelo terminal, dentro da pasta do projeto. O comando abaixo compila e executa o programa em seguida:

dotnet build
dotnet run

Se o LangVersion estiver correto, o terminal mostra os valores calculados pela lambda, a distância da tupla e os dados do estudante. Caso contrário, o compilador informa que o recurso não está disponível na versão atual da linguagem e sugere usar uma versão mais nova.

Esse erro é um bom sinal de diagnóstico. Ele confirma que o SDK reconhece o recurso, mas que o projeto ainda não liberou a versão preview.

Para voltar ao comportamento estável, basta remover a linha LangVersion do arquivo. Em seguida, rode dotnet build novamente e o compilador volta a usar a versão padrão do framework.

Quando a IDE não reconhece a sintaxe

Provavelmente sua IDE não vai reconhecer os comandos novos logo de início. Nesse caso, ela marca o código como possível erro, com sublinhado vermelho e mensagens de sintaxe inválida.

Editor de código marcando como erro a sintaxe do C# 12 preview, enquanto o terminal mostra o build concluído com sucesso
A IDE ainda acusa erro na sintaxe nova, mas o build termina sem falhas.

Mas o build não mente. Como você pode ver, mesmo com a IDE informando que a sintaxe não é válida, o programa compila e executa corretamente.

Isso acontece porque o editor e o compilador nem sempre estão na mesma versão. O dotnet build usa o compilador do SDK preview, enquanto a IDE pode carregar um analisador mais antigo.

Para reduzir esse descompasso, atualize a IDE para a versão preview correspondente. No anúncio do C# 12 preview, a Microsoft indicou o Visual Studio 17.6 preview como par do .NET 8 Preview 3.

Cuidados ao usar o C# 12 preview

Recursos em preview são ótimos para estudar e dar feedback, mas pedem cautela. Antes de adotar o C# 12 preview em qualquer projeto, considere os pontos a seguir.

  • Não use LangVersion em preview em projetos de produção.
  • Mantenha os experimentos em projetos separados ou em branches específicos.
  • Leia as notas de cada preview, porque a sintaxe pode mudar entre versões.
  • Fixe a versão do SDK com um arquivo global.json quando o time inteiro precisar testar a mesma build.

A documentação também alerta para outro risco. Usar uma versão da linguagem mais nova que a do seu framework de destino não tem suporte oficial e pode gerar erros difíceis de diagnosticar, tanto na compilação quanto na execução.

Por outro lado, quando a versão final do .NET 8 chega, o C# 12 passa a ser o padrão para projetos net8.0. Nesse momento, você pode remover a linha LangVersion e deixar o compilador escolher a versão automaticamente.

Conclusão

Trocar de versão de linguagem e de framework no .NET é um trabalho relativamente simples. Basta instalar o SDK certo, ajustar o TargetFramework e, quando necessário, definir o LangVersion.

Com o C# 12 preview, você conheceu construtores primários, aliases para qualquer tipo e lambdas com parâmetros padrão antes do lançamento oficial. Ainda assim, fique atento às breaking changes e às funcionalidades específicas de cada versão.

Se o seu projeto ainda roda em versões antigas, vale acompanhar também o fim do suporte delas, tema do artigo sobre o fim do suporte do .NET 8 e .NET 9.

FAQ

Preciso do .NET 8 para usar o C# 12?

Sim, porque cada versão do C# acompanha um framework. O C# 12 tem o .NET 8 como plataforma correspondente.

O que faz o valor preview no LangVersion?

Ele faz o compilador aceitar toda sintaxe válida da versão preview mais recente da linguagem. Use apenas para testes.

Por que minha IDE mostra erro se o build funciona?

O editor pode usar um analisador mais antigo que o compilador do SDK preview. Atualizar a IDE para a versão preview correspondente costuma resolver.

Os recursos em preview chegam iguais na versão final?

Nem sempre, já que a equipe ainda pode mudar ou remover recursos. O operador !! do C# 11, por exemplo, saiu antes do lançamento.

Posso usar LangVersion latest em produção?

A Microsoft não recomenda, porque o resultado depende do compilador instalado em cada máquina. Prefira o padrão do framework ou uma versão fixa.

Glossário

Termo Significado
SDK Kit de desenvolvimento com compilador, runtime e ferramentas de linha de comando do .NET
Preview Versão de pré-visualização, liberada antes do lançamento oficial para testes
LangVersion Propriedade do projeto que define qual versão do C# o compilador aceita
TargetFramework Propriedade que indica para qual versão do .NET o projeto é compilado
csproj Arquivo XML que descreve um projeto C# e suas configurações
Construtor primário Parâmetros declarados junto ao nome da classe e disponíveis em todo o corpo dela
Breaking change Mudança que quebra a compatibilidade com código escrito para versões anteriores

Fontes