C# 9.0 - Target-typed com expressões new
![]() |
Hoje veremos o novo recurso Target-type new expressions (expressões new com tipo de destino) do C# 9.0. |
O novo recurso do C# 9 chamado de Target-type new expressions tem como objetivo não exigir especificação de tipo para construtores quando o tipo é conhecido.
O termo Target-type ou tipo de destino significa que uma expressão obtém o tipo a partir do contexto no qual é usada.
Assim no C# 9.0 a expressão new obtém o tipo a partir do contexto, o que significa que você não precisa especificar o tipo de destino explicitamente para chamar um construtor. Vejamos um exemplo:
Usando o recurso target-type new expressions
Vamos criar um projeto Console e neste projeto criar a classe Aluno onde vamos definir um construtor padrão e um construtor com parâmetros:
public class Aluno
{
public Aluno() { }
public Aluno(string nome, string email)
{
Nome = nome;
Email = email;
}
public string Nome { get; set; }
public string Email { get; set; }
}
|
Para criar uma instância desta classe podemos usar o seguinte código:
Aluno aluno = new Aluno();
|
Podemos também criar um objeto usando o construtor parametrizado:
Aluno aluno = new Aluno("Maria", "maria@email.com");
|
Como a variável é inicializada diretamente com um novo aluno, podemos também usar a palavra-chave var para a declaração da variável como abaixo.
O compilador C# detecta, neste caso, o tipo Aluno para a variável, conforme você atribui uma nova instância de Aluno a ela. (A palavra-chave var foi introduzida em 2007 com C # 3.0 e .NET Framework 3.5 e funciona para variáveis locais.)
var aluno = new Aluno("Maria", "maria@email.com");
|
Nesta sintaxe, podemos notar que que a expressão new - que é a parte do lado direito do sinal de igual (=) - sempre requer o nome da classe.
A partir do C# 9.0 isso não é mais
necessário.
Se o tipo de destino já for conhecido do lado esquerdo do sinal de igual (=) podemos simplificar a declaração omitindo o tipo.
No entanto se você não usar a palavra-chave var no lado esquerdo do sinal de igual (=) o recurso não poderá ser usado.
Então, no C# 9.0, podemos criar uma instância de Aluno usando o construtor padrão da seguinte forma:
Aluno aluno = new();
|
Note que não precisamos especificar a classe Aluno do lado direito do sinal de igual (=), o compilador vai inferir o tipo obtendo-o do lado esquerdo do sinal de igual (=).
Podemos também chamar o construtor sobrecarregado da classe Aluno passando um nome e um email:
Aluno aluno = new("Maria", "maria@email.com");
|
No entanto, este recurso não pode ser usado quando usamos palavra-chave var para declarar a variável do tipo Aluno porque o compilador não tem como descobrir o tipo que você deseja criar:
var aluno = new("Maria", "maria@email.com") // NÃO FUNCIONA
|
Usando parâmetros opcionais no construtor
Podemos ainda definir a classe Aluno com um construtor com parâmetros opcionais conforme a seguir:
public class Aluno
{
public Aluno(string nome = null , string email = null )
{
Nome = nome;
Email = email;
}
public string Nome { get; set; }
public string Email { get; set; }
}
|
Chamar esse construtor com a nova expressão com tipo de destino funciona exatamente da mesma maneira que faríamos com uma nova expressão clássica, basta omitir o nome da classe no lado direito do sinal de igual (=).
Assim podemos chamar o construtor, por exemplo, sem nenhum argumento:
Aluno aluno = new();
|
Ou podemos usar apenas o nome:
Aluno aluno = new("Maria");
|
Ou podemos usar o nome e o email:
Aluno aluno = new("Maria", "maria@email.com");
|
Podemos também usar os argumentos nomeados para chamar apenas o email:
Aluno aluno = new(email : "maria@email.com");
|
Abaixo o código completo do exemplo:
Inicializadores de objeto
Podemos usar este recurso combinado com inicializadores de
objeto, o que é realmente útil para inicializar uma coleção sem repetir o
tipo em cada linha.
Veja como podemos fazer:
private List<Aluno> _listaAluno = new List<Aluno>
{
new("Maria"),
new("Pedro"),
new("Manoel")
};
|
Parâmetros de métodos
Podemos usar este recurso com parâmetros de métodos.
Neste caso o compilador também é capaz de inferir o tipo do contexto de chamada de um método. Ele assumirá automaticamente o tipo dos parâmetros do método.
Assim se tivermos a classe Aluno como um parâmetro de um método :
public static void Curso(Aluno aluno)
{
//codigo
}
|
Podemos usar o recurso desta forma:
static void Main(string[] args)
{
Curso(new("Maria"));
}
|
Usando com campos(fields)
Como é impossível declarar um campo com a palavra-chave var, podemos usar este recurso.
Os campos tendem a ter tipos genéricos complexos com nomes longos. Antes do C # 9.0, era tedioso repetir esses tipos em ambos os lados da atribuição do campo.
Antes:
protected readonly Dictionary<string, Aluno> _listaAlunos = new Dictionary<string, Aluno>();
|
A partir do C# 9.0 :
protected readonly Dictionary<string, Aluno> _listaAlunos = new();
|
Outros usos
Este recurso não funciona apenas para new, mas também em outras situações em que o tipo pode ser inferido a partir do contexto.
Um bom exemplo é com objetos que compartilham um tipo base. O tipo base pode ser determinado sem converter os objetos do lado direito em seu tipo base compartilhado.
Assim considerando o código abaixo:
public abstract class Animal
{
}
public class Cachorro : Animal
{
public Cachorro(string raca)
{
Raca = raca;
}
public string Raca { get; }
}
|
Podemos fazer assim:
static void Main(string[] args)
{
Cachorro cao = new("Lhasa Apso");
}
|
Vimos assim diferentes casos de uso para o novo recurso das expressões new com tipo de destino, e podemos indicar que o seu uso facilita bastante a escrita do código especialmente na inicialização direta de campo e propriedade onde a palavra-chave var não é uma opção a considerar.
Pegue o código
exemplo : TargetType_New.zip
"Disse-lhe Jesus: Porque me viste,
Tomé, creste; bem-aventurados os que não viram e creram."
João 20:29
Referências:
NET 6 - Global Using : Usando o modificador global na diretiva using