VAGAS DE EMPREGO

balta.io balta.io
  • Cursos
  • Carreiras
  • Para sua Empresa
  • Livros
    • Background Services
    • Blazor com .NET 8
    • Segurança em APIs
    • Futuro do C# 12
    • Nullable Types
    • Clean Code
  • Blog

Seja Premium
balta.io

  • Cursos
  • Carreiras
  • Para sua Empresa
  • Agenda
  • Livros
    • Background Services
    • Blazor com .NET 8
    • Segurança em APIs
    • Futuro do C# 12
    • Nullable Types
    • Clean Code
  • Blog
  • Player
Seja Premium

Entre ou Cadastre-se

  • Home
  • Artigos
  • Novidades do C# 12 - Primary Constructors


👉 Temos uma versão mais atualizada deste artigo no nosso novo Blog

Novidades do C# 12 - Primary Constructors

O C# 12 está previsto para ser lançado em Novembro de 2023, junto com o .NET 8, mas já tivemos uma prévia das suas novidades no Preview 4 do .NET 8 e vamos conferir aqui.

Antes de começar

É importante salientar que este recuso está disponível no .NET 8 Preview 3, ou sejá é apenas uma pré-visualização do que poderá ser este recurso.

Já vimos casos no passado, como o !! que foram removidos da versão final, então não se apegue muito aos novos recursos em sí até a versão final.

É importante frisar também que o .NET 8 só sai em Novembro de 2023, muita coisa pode mudar até lá e você precisa instalar a versão Preview 3 ou superior para testar estas funcionalidades.

Como instalar o .NET 8

Você pode fazer o download do .NET 8 no site oficial da Microsoft, utilizando a URL abaixo.

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

Verificando a versão instalada

Com o .NET instalado, basta fechar seus terminais e abrir novamente, seguido pela execução do comando abaixo para verificar a versão instalada.

dotnet --version
## 8.0.100-preview.3.23178.7

Além disso, o .NET 8 ainda mantém o C# 11 como linguagem padrão, então é preciso habilitar uma funcionalidade chamada Language Preview no arquivo .csproj do seu projeto.

Isto é feito pela configuração chamada LangVersion cujo temos que atribuir o valor preview, como mostrado abaixo.

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

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework> 👈 Garantir que o .NET está na V8
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <LangVersion>preview</LangVersion> 👈 Adiciona esta linha
  </PropertyGroup>

</Project>

IMPORTANTE: Provavelmente sua IDE não vai reconhecer os comandos novos, identificando eles como possíveis erros.

Construtores Primários

Se você já trabalha com C# e está atualizado sobre as melhorias na linguagem, provavelmente já utilizou o recurso de construtores primários nas structs e/ou records.

Porém, no C# 12 teremos esta novidade inclusa também nas classes. Isto mesmo, agora podemos simplificar muito a criação de classes utilizando construtores primários.

// Exemplo de construtor primário
// em Records
public record Person(int Id, string Name);

// Exemplo de construtor primário
// em Structs
public struct Person(int Id, string Name);

// Exemplo de construtor primário
// em Classes (⭐️ novidade do C# 12)
public class Person(int Id, string Name);

O que e um é um construtor?

Construtor ou Constructor em inglês é o nome dado a um método especial de uma classe, que é executado toda vez que um objeto com base nesta classe é criado e que obrigatóriamente deve ter o mesmo nome da classe.

Então, supondo que temos uma classe chamada Name, podemos ter um Construtor chamado Name nesta classe.

public class Name
{
	public Name()
	{
		// Método Construtor
	}

    public string FirstName { get; set; }
    public string LastName { get; set; }
}

Desta forma, toda vez que instanciarmos um objeto a partir desta classe, o método Name será chamado. Note que ele não tem retorno e pode ou não conter parâmetros.

var name = new Name();
// Neste momento o construtor é chamado

var name = new Name {
	FirstName = "André",
	LastName = "Baltieri",
};
// Outro exemplo

Sempre que criamos um construtor sem parâmetros, ele recebe o nome de Parameterless, que significa exatamente Sem Parâmetros em inglês, porém, é plenamente possível criar um construtor com parâmetros.

public class Name
{
	public Name(string firstName, string lastName)
	{
		FirstName = firstName;
		LastName = lastName;
	}

    public string FirstName { get; set; }
    public string LastName { get; set; }
}

O único detalhe é que uma vez definido um (E apenas um) construtor com parâmetros, somos obrigados a informar os valores já na instância do objeto.

var name = new Name();
// ❌ ERRO - Precisa informar os valores

var name = new Name("André", "Baltieri");
// ✅ OK - Informou os valores

Por fim, podemos combinar construtores, tendo mais de um para nossas classes, incluindo um com e outro sem parâmetros.

public class Name
{
	public Name() { }

	public Name(string firstName, string lastName)
	{
		FirstName = firstName;
		LastName = lastName;
	}

    public string FirstName { get; set; }
    public string LastName { get; set; }
}

No exemplo acima, temos uma sobrecarga de método, dando a possibilidade de informar ou não argumentos na chamada do método.

var name = new Name();
// ✅ OK - Passa pelo Parameterless

var name = new Name("André", "Baltieri");
// ✅ OK - Informou os valores

É comum também, vermos construtores como o modificador protected ao invés do public. Isto ocorre por que o Entity Framework por exemplo, exige um construtor parameterless para instância de objetos.

public DbSet<Product> Products { get; set; }
// ❌ - Vai falhar se Product não tiver um construtor parameterless

Entretanto, uma boa recomendação é explicitar no construtor da sua classe, quais propriedades são obrigatórias para mesma funcionar.

Para resolver esta situação, podemos utilizaro protected no construtor parameterless, afinal ele só será usado por uma classe proxy que derivará da classe base no EF.

public class Name
{
	// 👇 Agora é protected
	protected Name() { } 

	public Name(string firstName, string lastName)
	{
		FirstName = firstName;
		LastName = lastName;
	}

    public string FirstName { get; set; }
    public string LastName { get; set; }
}

Desta forma podemos evitar que nossa classe seja instanciada sem valores for do seu escopo, mas ainda permitimos que classes filhas faça uso do construtor parameterless.

var name = new Name();
// ❌ Erro - Não pode instanciar sem passar valores

var name = new Name("André", "Baltieri");
// ✅ OK - Informou os valores

public DbSet<Product> Products { get; set; }
// ✅ - Proxy das classes vão funcionar

Para finalizar, podemos fazer uso dos Optional Parameters, para ter um efeito parecido com os de cima.

public class Measurement
{
	public Measurement(
		int width = 0,  // 👈 Parâmetro opcional, já possui um valor
		int height = 0) // 👈 Parâmetro opcional, já possui um valor
	{
  	}

	public int Width { get; set; }
	public int Height { get; set; }
}

Isto torna a instância do objeto mais maleável, podendo ou não informar os valores definidos no construtor.

// Inicia com os valores padrão
var measurement = new Measurement(); 

// Inicia com 10 para width e 0 para height
var measurement = new Measurement(10); 

// Inicia com 10 para width e 10 para height
var measurement = new Measurement(10, 10); 

De qualquer forma, as possibilidade são muitas, vai do que você precisa para o seu cenário e de como quer tratar a instância do seu objeto.

O que são Primary Constructors?

Legal, mas supondo que eu tenha uma classe com duas propriedades apenas, porém, estas propriedades devem ser obrigatórias, meu código ficaria assim?

public class Name
{
	public Name(string firstName, string lastName)
	{
		FirstName = firstName;
		LastName = lastName;
	}

    public string FirstName { get; set; }
    public string LastName { get; set; }
}

Pois é! Muito código para algo realmente simples, não acha? Inclusive, é sempre uma boa recomendação ver se os records ou structs podem fazer o trabalho pela sua classe.

public record Name(string FirstName, string LastName);
public struct Name(string FirstName, string LastName);

Como podemos ver acima, tanto os records quanto os structs possuem um recurso chamado Primary Constructors ou construtores primários.

Este recurso permite que sequer precisemos abrir chaves para criação da classe, ou seja, tudo é definido na estrutura inicial.

var name = new Name();
// ❌ ERRO - Precisa informar os valores

var name = new Name("André", "Baltieri");
// ✅ OK - Informou os valores

Então, um construtor primário, nada mais é do que a possibilidade de explicitar alguns valores obrigatórios já na definição da classe, simplificando o código.

Desta forma, no C# 12, teremos a inclusão dos Primary Constructors para classes, tornando a sintaxe ainda mais enxuta.

// Podemos usar a sintaxe reduzida
public class Name(string FirstName, string LastName);

// Ou mesmo expandir e ter comportamento na classe
public class Name(string FirstName, string LastName)
{
    
}

Como resultado, temos um comportamento similar aos anteriores, onde somos obrigados a informar os valores na instância do objeto.

var name = new Name();
// ❌ CS7036: There is no argument given that corresponds to the required parameter 'FirstName' of 'Name.Name(string, string)'

var name = new Name("André", "Baltieri");
✅ - OK

Primary Constructors para classes

Existe uma diferença nos construtores primários para as classes em relação a mesma funcionalidade para records e structs.

No caso dos Recors e Struts, ao utilizar o recurso de construtor primário temos automaticamente uma propriedade pública com o mesmo nome, criada de forma automática.

public record Name(string FirstName, string LastName);

var name = new Name("André", "Baltieri");
Console.WriteLine(name.FirstName);
Console.WriteLine(name.LastName);

Neste mesmo exemplo, ao alterar de record para class, mudamos o comportamento, visto que os parâmetros dos Primary Constructors são identificados como membros privados em uma classe.

IMPORTANTE Este comportamento pode ser alterado até a versão final do C# 12 que está prevista para Novembro de 2023.

//      👇 utilizando class ao invés de record
public class Name(string FirstName, string LastName);

var name = new Name("André", "Baltieri");
Console.WriteLine(name.FirstName); // ❌ FirstName não existe
Console.WriteLine(name.LastName); // ❌ LastName não existe

Para ter o mesmo comportamento de um record ou struct, precisamos exportar os argumentos, explicitando o acesso dos mesmos com o modificado public.

public class Name(string firstName, string lastName)
{
    public string FirstName => firstName;
    public string LastName => lastName;
}

Desta forma, agora temos dois parâmetros de entrada, que são privados por padrão e consequentemente dois membros para saída, que são públicos.

var name = new Name("André", "Baltieri");
Console.WriteLine(name.FirstName); // ✅
Console.WriteLine(name.LastName); // ✅

Note também que não há necessidade de nomear os parâmetros com inicial maiúscula, já que eles sempre serão privados.

public record Name(string FirstName, string LastName);
// Recomendo usar maiúscula já que são membros públicos

var name = new Name();
Console.WriteLine(name.FirstName);
Console.WriteLine(name.LastName);

// No caso das classes o comportamento inverte
// recomendo usar minúscula pois são privados
public class Name(string firstName, string lastName)
{
    public string FirstName => firstName;
    public string LastName => lastName;
}

var name = new Name();
Console.WriteLine(name.FirstName);
Console.WriteLine(name.LastName);

Herança e Primary Construtors

Caso haja necessidade de herdar de uma classe que contém um Primary Constructor, precisamos fornecer os dados para mesma, assim como já fazemos hoje com construtores que não são parameterless.

public class Student(string firstName, string lastName, int grade)
    : Name(firstName, lastName)
{
}

Note que ao utilizar a herança “:” somos obrigados a informar o firstName e lastName, e neste caso, precisamos receber eles também no Student.

Um ponto importante e interessante aqui, é que a classe Student possui uma propriedade a mais, chamada Grade e que não está sendo exportada, logo, esta propriedade não poderá ser acessada.

var student = new Student("André", "Baltieri", 10);

Console.WriteLine(student.FirstName); // ✅ - Publica no Name
Console.WriteLine(student.LastName); // ✅ - Publica no Name
Console.WriteLine(student.Grade); // ❌ - Somente Student conhece

Construtores Parameterless e Primary Constructors

Outro ponto interessante que testei foi o cenário onde temos a herança de uma classe com um construtor primário mas queremos ter um construtor parameterless.

Mais especificamente, vamos supor que a classe Name tenha um construtor primário mas a classe Student que herda dela tenha um construtor parameterless.

public class Student(string firstName, string lastName, int grade)
    : Name(firstName, lastName)
{
		// Construtor com valores padrões
    public Student() : this("First", "Last", 5)
    {
    }

		public int Grade => grade;
}

Neste caso, podemos utilizar o this para inicializar o construtor parameterless e informar os valores padrão para Name, visto que eles são obrigatórios.

Conclusão

Os construtores primários com certeza são uma ótima adição as classes no C#, tornando ainda mais simples e fácil utilizá-las.

Populares

Priority Queue

Priority Queue ou fila prioritária é um tipo de lista inclusa no C# 10 que permite que seus itens...


Implicit Operators no C#

Implicit Operators permitem adicionar comportamentos de conversão a objetos Built In ou complexos...


ASP.NET 5 – Autenticação e Autorização com Bearer e JWT

Este artigo atualmente utiliza a versão 5.0.0-rc.1 do ASP.NET/.NET, o que significa que ainda não...


Clean Code - Guia e Exemplos

Saiba como manter seu código limpo (Clean Code) seguindo algumas práticas sugeridas pelo Robert C...


Git e GitHub - Instalação, Configuração e Primeiros Passos

Git é um sistema de controle de versões distribuídas, enquanto GitHub é uma plataforma que tem o ...


Compartilhe este artigo



Conheça o autor

André Baltieri

André Baltieri

Microsoft MVP

Me dedico ao desenvolvimento de software desde 2003, sendo minha maior especialidade o Desenvolvimento Web. Durante esta jornada pude trabalhar presencialmente aqui no Brasil e Estados Unidos, atender remotamente times da ?ndia, Inglaterra e Holanda, receber 8x Microsoft MVP e realizar diversas consultorias em empresas e projetos de todos os tamanhos.





3.133

Aulas disponíveis

292

horas de conteúdo

76.461

Alunos matriculados

53.012

Certificados emitidos





Comece de graça agora mesmo!

Temos mais de 21 cursos totalmente de graça e todos com certificado de conclusão.

Começar


Prefere algo mais Premium?

Conheça nossos planos



Premium anual

Compra única, parcelada em até
12x no cartão de crédito


12x R$

99

,79

=R$ 1.197,44
  • 1 ano de acesso
  • Acesso à todo conteúdo
  • Emissão de Certificado
  • Tira Dúvidas Online
  • 67 cursos disponíveis
  • 10 carreiras disponíveis
  • 161 temas de tecnologia
  • Conteúdo novo todo mês
  • Encontros Premium

Começar agora

Política de privacidade



Precisa de ajuda?

Dúvidas frequentes



  • Posso começar de graça?

    Sim! Basta criar sua conta gratuita no balta.io e começar seus estudos. Nós contamos com diversos cursos TOTALMENTE gratuitos e com certificado de conclusão.

  • Vou ter que pagar algo?

    Nós temos cursos gratuitos e pagos, porém você não precisa informar nenhum dado de pagamento para começar seus estudos gratuitamente conosco. Os cursos gratuitos são completos e com certificado de conclusão, você não paga nada por eles.

    Porém, caso queira algo mais Premium , você terá acesso à diversos benefícios que vão te ajudar ainda mais em sua carreira.

  • Por onde devo começar?

    Siga SEMPRE as nossas Carreiras , elas vão te orientar em todos os sentidos. Os cursos já estão organizados em categorias e carreiras para facilitar seu aprendizado.
    Nossa sugestão para aprendizado é começar pelo Backend e seguindo para Frontend e Mobile.

    • Backend
    • Frontend
    • Mobile

  • Os cursos ensinam tudo que preciso?

    Nenhum curso no mundo vai te ensinar tudo, desculpa ser sincero! Os cursos são uma base, eles fornecem por volta de 30% do que você precisa aprender, o resto é com você, com dedicação e MUITA prática.

  • O que eu devo estudar?

    Java ou .NET? Angular ou React? Xamarin ou Flutter? A resposta é simples e direta: "Você já sabe o básico?"

    Se você ainda não sabe BEM o básico, ou seja, os fundamentos, OOP, SOLID, Clean Code, está perdendo tempo estudando Frameworks ou até coisas mais avançadas como Docker. Foque nos seus objetivos primeiro.
    Agora se você está indeciso sobre qual Framework estudar, a boa notícia é que o mercado neste momento está bem aquecido e você tem várias oportunidade. Desta forma o que levaríamos em conta para tomar esta decisão seria:

    • Já sei o básico
    • O Framework/Tecnologia tem mercado onde eu estou (região)
    • O Framework/Tecnologia é utilizado em uma empresa onde quero atual
    • O Framework/Tecnologia resolve meu problema
    • Eu gosto de utilizar o Framework/Tecnologia

  • Estou pronto para estudar no balta.io?

    Com certeza! O primeiro passo é começar e você pode fazer isto agora mesmo!

    Começar de graça

Ainda tem dúvidas?





Assine nosso Newsletter

Receba em primeira mão todas as nossas novidades.

Cadastrar


balta.io

Sobre

  • Como funciona?
  • Seja Premium
  • Agenda
  • Blog
  • Todos os cursos

Cursos

  • Frontend
  • Backend
  • Mobile
  • Fullstack

Suporte

  • Termos de uso
  • Privacidade
  • Cancelamento
  • Central de ajuda

Redes Sociais

  • Telegram
  • Facebook
  • Instagram
  • YouTube
  • Twitch
  • LinkedIn
  • Discord