Novidades do C# 8.0
Ta saindo versão nova do forno! 💻
C# 8.0 e .Net Core 3.0 já estão disponíveis!
Hoje quero mostrar um pouco das features novas que foram e/ou ainda vão ser adicionadas na versão 8.0.
Para quem quiser testar, está disponível no Visual Studio 2019 Preview, basta instalar e fazer o teste. No fim do artigo tem algumas instruções e links.
Obs.: Os tópicos marcados com um * não estão disponíveis ainda na versão preview
Nullable reference types
O intuito dela é produzir warnings ao identificar um objeto possivelmente nulo no seu código, que possa resultar em um NullReferenceException
.
Juntamente com isso, é possível agora tornar uma string em um “nullable type”. Aqueles que já conhecem sabem que diferente de um int, que para ser nullable é necessário estar como int?
ou Nullable<int>
, strings já são nullables em sua raiz (por serem variáveis de referência e não de valor).
Então para quê vou tornar meu string em um nullable type?
Bom… É mais para ter um maior cuidado com nossa famosa exceçãoNullReferenceException
, assim podemos diminuir as incidências delas por conta de esquecer de checar se o objeto está nulo ou não.
Colocar nullable ou não, não vai barrar você de atribuir null
em sua string, mas com certeza o intellisense vai pintar de amarelo e criar warnings no seu código quando detectar um perigo! Veja as diferenças:
Outra coisa legal, pelo menos nesta versão preview, é que não é “obrigatório” o uso dessa feature, ela somente é habilitada caso você coloque a tag #nullable enable
no topo da sua classe.
Ou se quiser habilitar para o projeto todo, basta colocar no seu .csproj a tag:
<NullableReferenceTypes>true</NullableReferenceTypes>
O que foi bem sensato por parte da Microsoft, eu por exemplo, ficaria bem irritado ao abrir meu projeto e ver centenas de warnings para todos os lados.
IAsyncEnumerable<T>
Conhecemos a interface IEnumerable<T>
e agora foi introduzido o IAsyncEnumerable<T>
que torna a nossa coleção em uma coleção assíncrona!
Agora não é mais necessário gerar um Task<IEnumerable<T>>
, o que tornava um pouco chato tanto a implementação quanto a própria sintaxe.
Array Slicing
Chega de usar o nosso grande System.Linq
para fazer slicing de array!
Antes usávamos muito os métodos Take()
eSkip()
para conseguir selecionar uma porção específica de um array ou mais especificamente de um IEnumerable<T>
. A partir do C# 8.0 isso talvez não seja mais necessário!!
E é bem fácil de escrever e compreender, temos duas sintaxes para isso:
Recursive Patterns*
Com essa nova feature podemos melhorar o nosso switch case, passando várias referências/valores dentro do switch.
Em poucas palavras (ou códigos) hoje usamos switch(variavel)
, agora podemos usar switch(variavel1, variavel2, variavel3)
e ter cases para cada variação dentre essas variáveis:
switch(p.Nome, p.Sobrenome)
{
case (string n, string s):
return $"{n} {s}";
case (string n, null):
return n;
case (null, string s):
return $"Sr. {s}";
case (null, null):
return "Desconhecido";}
Switch expressions*
Ainda falando de switch, por conta do novo recursive pattern é possivel que os cases ficam bem maiores que o esperado, portanto foram adicionados a possibilidade do uso de expressões para os cases.
Assim como utilizamos em métodos (feature do C# 7.0), podemos aplicar o mesmo agora dentro de cada condição do nosso switch.
Basta usar os tokens =>
que fica bem melhor pra dar nosso famoso return
:
return (p.Nome, p.Sobrenome) switch
{
(string n, string s) => $"{n} {s}",
(string n, null) => n,
(null, string s) => $"Sr. {s}",
(null, null) => "Desconhecido"}
Implicity typed new-expressions*
Hoje quando definimos um array de um determinado objeto, é necessário escrever por exemplo new Pessoa("nome", "sobrenome")
para todos os itens criados dentro do array.
O que essa feature faz é basicamente excluir a necessidade de escrever isso, já que está “tipado”, o compilador já vai entender que se trata daquele objeto, portanto inibindo a escrita de “Pessoa” para: new ("nome", "sobrenome")
Pessoa[] pessoas = new
{
new ("Henrique", "Dal Bello"),
new ("Bill", "Gates"),
new ("Mark", "Zuckerberg")};
Default interface members
Os contratos de interface exigem que cada classe que o implementa contenha os métodos definidos nela, portanto, toda vez que adicionarmos um novo método nela, automaticamente haverá erros subindo por conta de classes que ainda não implementam.
No C# 8.0, podemos definir um método default, sim, um método único que caso a classe não tenha o seu próprio implementado (quase como um override), ele vai utilizar o que foi definido na interface.
public interface ILogger
{
void Log(string mensagem);
void Log(Exception ex) => Log(ex.Message); //Default}
Testando o preview do C# 8.0
Pra quem quiser testar, basta baixar o Visual Studio 2019 Preview, o SDK do .net core 3.0 e ser feliz!
Na hora que criar o projeto de teste, não esqueça de mudar o framework para o .Net Core 3.0 lá em properties do projeto e também habilitar o C# 8.0 na aba lateralBuild > Advanced
mudando para C# 8.0 (beta).
Visual Studio 2019 Preview:
SDK:
Fontes:
https://blogs.msdn.microsoft.com/dotnet/2018/12/05/take-c-8-0-for-a-spin/