
Esse é o 7º post da série sobre C# 7. Pra acompanhar a série você pode seguir a tag C#7 no blog ou voltar no post que agrega a série.
Discards
No C#7 foi criada uma forma de jogar fora um valor, de descartar um valor. Isso veio com o uso de um caractere muito utilizado em outras linguagens, o _
.
Existem alguns contextos onde isso é interessante, onde você quer descartar um valor, especificamente na hora de obter valores a partir de descontrução (de objetos ou tuplas), pattern match, no retorno de valores com out
, ou simplesmente em um lugar onde você não quer guardar algum valor, de forma livre. O último caso é menos comum e interessante, então vamos ver os 3 primeiros.
O importante nos exemplos a seguir é entender que a variável _
não aloca memória e é write only, ou seja, você não consegue ler seu valor (lógico, ele foi descartado).
Desconstrução
Imagine que você tem uma função que separa um array entre o primeiro item e os restantes, mais conhecidos como head
e tail
, mas que, em uma operação específica, você precisa apenas da head
. Para economizar memória, deixar o código mais limpo e não acabar alocando uma variável desnecessária, que poderia gerar confusão e bugs, descartamos o tail
, colocando o valor na variável de descarte, a _
.
var (head, _) = Separa(new[] { 1, 2, 3 });
Pattern matching
Em pattern matching você pode também ter valores que não lhe importam. Lembrando da função que separa head
e tail
como falei antes, vamos ver sua implementação usando pattern matching e com descarte do _
:
(T head, T[] tails) Separa<T>(T[] array) { switch (array) { case null: case object _ when array.Length == 0: return (default, new T[] { }); case object _ when array.Length == 1: return (array[0], new T[] { }); default: return (array[0], array.Skip(1).ToArray()); } }
Note que nos segundo e terceiros case não estou checando o tipo, apenas checando o tamanho do array, então estou descartando o valor encontrado no match; Não me importa o fato de ele ser um object, então descarto-o.
O descarte com pattern matching também funciona com if
, assim como com a descontrução de objetos.
Observação: Essa é uma implementação de exemplo, eu provavelmente a escreveria de outra forma, mas ela cumpre o objetivo deste artigo.
Parâmetros out
Em métodos que retornam valores via parâmetros out
, você pode descartar o valor passando-o para o _
. No exemplo a seguir, quero validar se uma string pode ser convertida para um número, mas não me importa o número, então discarto-o:
if (int.TryParse("1", out var _)) WriteLine("É um número");
Observações
Note que se houver uma variável _
declarada e em contexto, ela terá prioridade, ou seja, ela receberá o valor, e a memória será alocada.
Além disso, note que a variável _
pode assumir qualquer tipo, e pode receber vários valores incompatíveis entre si, e se você possui um _
declarado, o tipo dessa variável poderá ser imcompatível com o valor que você quer descartar.
Por exemplo, imagine que a função a seguir retorna uma tupla com um inteiro e uma string, e quero descartar ambos:
var (inteiro, texto) = Obtem(); var (_, _) = Obtem();
A primeira chamada não descarta nenhum valor, já na segunda ambos são descartados. Mas, se você já tiver um _
declarado, ela vai falhar, por exemplo, neste caso, o código não compila:
int _; var (_, _) = Obtem();
Você consegue ler sobre discards nos docs de Discards no Microsoft Docs.