Novidades do C# 7, 7.1, 7.2 e 7.3
Olá, neste artigo eu vou escrever um resumo das novidades que eu acho mais relevantes que vieram no C# nas versões 7, 7.1, 7.2 e 7.3.
out Variables
Antes.
int result;
if (int.TryParse(input, out result))
{
Console.WriteLine(result);
}Depois.
if (int.TryParse(input, out var result))
{
Console.WriteLine(result);
}Tuples
Declaração de variáveis, antes.
var result = new Tuple<bool, string>(false, "An error has occurred");
Console.WriteLine($"{result.Item1}, {result.Item2}");Depois.
var result = (Successfully: false, Message: "An error has occurred");
Console.WriteLine($"{result.Successfully}, {result.Message}");Chamada de método, antes.
var result = DoSomething();
Console.WriteLine($"{result.Item1}, {result.Item2}");
Tuple<bool, string> DoSomething() => new Tuple<bool, string>(false, "An error has occurred");Depois.
var (successfully, message) = DoSomething();
Console.WriteLine($"{successfully}, {message}");
(bool Successfully, string Message) DoSomething() => (false, "An error has occurred");Discards
- não aloca memória;
- é write only;
variáveis out que não serão usadas, antes.
var successfully = int.TryParse(input, out var result);Depois.
var successfully = int.TryParse(input, out _);variáveis em pattern matching que não serão usadas, antes.
switch (true)
{
case object n when successfully:
return "Successfully";
default:
return "An error has occurred";
}Depois.
switch (true)
{
case object _ when successfully:
return "Successfully";
default:
return "An error has occurred";
}variáveis desconstruídas que não serão usadas, antes.
var (successfully, message) = DoSomething();
if (successfully)
{
return;
}Depois.
var (successfully, _) = DoSomething();
if (successfully)
{
return;
}Local functions
- pode ser
async; - pode usar iterators com
yield; - pode conter outra função local;
- pode conter um bloco ou uma expressão;
- pode ser genérica e pode restringir os tipos genéricos;
- pode usar variáveis e parâmetros genéricos que estejam no escopo da função que ela foi criada;
- pode usar parâmetros
refeout; - não pode mudar o fluxo da função externa, por exemplo com uso de
goto,break,continuee etc; - não causam alocações locais como declaração de
FuncouAction;
Antes.
public void LogInfo(in string message)
{
Log("Info", message);
}
private static void Log(in string level, in string message)
{
Console.WriteLine($"{level} -> {message}");
}Depois.
public void LogInfo(string message)
{
Log("Info");
void Log(in string level)
{
Console.WriteLine($"{level} -> {message}");
}
}Mais expression-bodied
Esta feature feio da versão 6, e na versão 7 eles adicionaram em construtures, finalizadores e propriedades.
Antes.
public class User
{
private readonly string name;
public User(in string name)
{
this.name = name;
}
~User()
{
Console.WriteLine("User finalized.");
}
public string Name
{
get
{
return this.name?.ToUpper() ?? string.Empty;
}
}
}Depois.
public class User
{
private readonly string name;
public User(in string name) => this.name = name;
~User() => Console.WriteLine("User finalized.");
public string Name => this.name?.ToUpper() ?? string.Empty;
}throw Expressions
Agora podemos utilizar throw em uma operação de null coalesce e em expression bodied members.
Antes.
public class User
{
private string name;
public string Name
{
set
{
if (value == null)
{
throw new ArgumentNullException(nameof(value), "Name cannot be null");
}
this.name = value;
}
get
{
throw new NotImplementedException();
}
}
}Depois.
public class User
{
private string name;
public string Name
{
set => this.name = value ?? throw new ArgumentNullException(nameof(value), "Name cannot be null");
get => throw new NotImplementedException();
}
}async Método Main
Antes.
public class Program
{
public static void Main(string[] args) => MainAsync()
.GetAwaiter()
.GetResult();
private static Task MainAsync() => Task.CompletedTask;
}Depois.
public class Program
{
public static Task Main(string[] args) => Task.CompletedTask;
}default Literal expressions
Em parâmetros opcionais, antes.
public class User
{
public User(in string name)
{
this.Id = default(uint);
this.Name = name;
}
public uint Id { get; private set; }
public string Name { get; }
public override string ToString() => default(string);
public User UpdateUser(in uint id, in string name = default(string)) => new User(name ?? this.Name)
{
Id = id,
};
}Depois.
public class User
{
public User(in string name)
{
this.Id = default;
this.Name = name;
}
public uint Id { get; private set; }
public string Name { get; }
public override string ToString() => default;
public User UpdateUser(in uint id, in string name = default) => new User(name ?? this.Name)
{
Id = id,
};
}Argumentos nomeados não finais
Antes.
UpdateUser(id: 1, name: name);Depois.
UpdateUser(id: 1, name);Técnicas para escrever código eficiente e seguro
in o parâmetro é passado por referência só que readonly;
ref o parâmetro é passado por referência read and write;
ref readonly o retorno do método é por referência e não pode ser alterado;
struct readonly a estrutura é readonly evitando quando um método é acessado uma cópia desnecessária;
protected internal permite classes derivadas ou no mesmo assembly;
private protected permite classes derivadas e no mesmo assembly;
Pattern Matching terá um artigo só para ele, e será sempre atualizado com as novas versões do C#.
Mais exemplos
Abaixo uma lista de projetos que você pode ver as novidades do C# em exemplos reais.
♟ Chess é uma console app feita com ASCII art. 🐷 Hawk (api) é sistema de finança pessoal. Http.Query.Filter é uma lib para fazer filtros baseado no StrongLoop da IBM.
Obrigado pela visita 🙂!
Comentários