Esse é o 22º post da série sobre C# 7, e o oitavo sobre C# 7.2, além do último 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.

Lembrando que 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 post 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. Nós 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 post sobre estruturas imutáveis.

Você consegue ler um pouco mais sobre este assunto somente no Github e também neste outro artigo, também no Github. Não encontrei docs sobre isso no Microsoft Docs, então, só lá mesmo.