Back-End

22 mai, 2018

Novidades do C# 7.2: operador ternário com ref

Publicidade

Para utilizar as versões minor do C# (como a 7.1 ou 7.2), você precisa habilitá-la nos atributos do projeto. Veja neste artigo como fazê-lo e também como habilitar na solution inteira pra não ter que ficar configurando cada projeto individualmente.

Novidades do C# 7.2: Operador ternário com ref

No C# 7.0, foi criada a variável local por referência, a ref local, mas até o C# 7.2 não era possível usar o operador ternário com ref locals. A alternativa era usar um método, como:

ref T Escolha(bool condicao, ref T consequencia, ref T alternativa)
{
    if (condicao)
         return ref consequencia;
    else
         return ref alternativa;
}

E em seguida, invocá-lo dessa forma:

ref var r = ref Escolha(arr != null, ref arr[0], ref outroArr[0]);

No entanto, esse código vai causar uma exception, porque todos os valores serão avaliados antecipadamente, ou seja, o arr, mesmo sendo nulo, vai ter sua primeira posição buscada, para que possa ser passado para o método Escolha.

Gostaríamos que isso só acontecesse se ele não fosse nulo, ou seja, precisamos que essa avaliação seja lazy. É pra isso que o operador ternário serve, mas, como eu disse antes, até o C# 7.2 ele não podia ser usado com referências. A opção que sobrava era usar um horrendo if.

Com o C# 7.2 já temos a opção do operador ternário, então o código acima ficaria:

ref var r = ref (arr != null ? ref arr[0] : ref outroArr[0]);

(Sim, ref pra todo lado! Você achou que código eficiente era bonito?)

Pontos interessantes do operador ternário com ref

Como o resultado de um operador ternário com ref é uma referência, podemos fazer coisas divertidas com ele, como passar um valor pra referência:

(arr != null ? ref arr[0] : ref outroArr[0]) = 1;

O exemplo acima vai setar o valor do array correto, sem cópia alguma. Também podemos invocar métodos, sem cópia alguma de valores:

(arr != null ? ref arr[0] : ref outroArr[0]).MetodoDaEstrutura();

E, se o método for chamado sobre uma estrutura, não há cópia também. No exemplo abaixo, campoReadOnly é um campo somente leitura, e seu tipo é uma estrutura também somente leitura.

(arr != null ? ref arr[0] : ref outroArr[0].campoReadOnly).MetodoDaEstruturaReadonly();

Pra entender como essa cópia é evitada, veja o artigo sobre estruturas imutáveis. Você consegue ler um pouco mais sobre este assunto somente no Github e neste outro artigo, também no Github. Não encontrei docs sobre isso no Microsoft Docs, então, só lá mesmo.

***

Este artigo foi produzido em parceria com a Lambda3. Leia outros conteúdos no blog da empresa: blog.lambda3.com.br