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.

Conteúdo:
out Variables

Antes.

1
2
3
4
5
int result;
if (int.TryParse(input, out result))
{
Console.WriteLine(result);
}

Depois.

1
2
3
4
if (int.TryParse(input, out var result))
{
Console.WriteLine(result);
}
Tuples

Declaração de variáveis, antes.

1
2
var result = new Tuple<bool, string>(false, "An error has occurred");
Console.WriteLine($"{result.Item1}, {result.Item2}");

Depois.

1
2
var result = (Successfully: false, Message: "An error has occurred");
Console.WriteLine($"{result.Successfully}, {result.Message}");

Chamada de método, antes.

1
2
3
4
var result = DoSomething();
Console.WriteLine($"{result.Item1}, {result.Item2}");

Tuple<bool, string> DoSomething() => new Tuple<bool, string>(false, "An error has occurred");

Depois.

1
2
3
4
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.

1
var successfully = int.TryParse(input, out var result);

Depois.

1
var successfully = int.TryParse(input, out _);

variáveis em pattern matching que não serão usadas, antes.

1
2
3
4
5
6
7
switch (true)
{
case object n when successfully:
return "Successfully";
default:
return "An error has occurred";
}

Depois.

1
2
3
4
5
6
7
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.

1
2
3
4
5
var (successfully, message) = DoSomething();
if (successfully)
{
return;
}

Depois.

1
2
3
4
5
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 ref e out;
  • não pode mudar o fluxo da função externa, por exemplo com uso de goto, break, continue e etc;
  • não causam alocações locais como declaração de Func ou Action;

Antes.

1
2
3
4
5
6
7
8
9
public void LogInfo(in string message)
{
Log("Info", message);
}

private static void Log(in string level, in string message)
{
Console.WriteLine($"{level} -> {message}");
}

Depois.

1
2
3
4
5
6
7
8
9
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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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.

1
2
3
4
5
6
7
8
9
10
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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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.

1
2
3
4
5
6
7
8
9
10
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.

1
2
3
4
5
6
7
8
public class Program
{
public static void Main(string[] args) => MainAsync()
.GetAwaiter()
.GetResult();

private static Task MainAsync() => Task.CompletedTask;
}

Depois.

1
2
3
4
public class Program
{
public static Task Main(string[] args) => Task.CompletedTask;
}
default Literal expressions

Em parâmetros opcionais, antes.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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.

1
UpdateUser(id: 1, name: name);

Depois.

1
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;

nota: 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 🙂!