Enquanto a atenção se volta mais às grandes alterações como os métodos de interface padrão e referências nulas, muitas melhorias pequenas também estão incluídas no C# 8. Temos aqui alguns exemplos do que estará na futura versão do C#.
Novos Operadores de Atribuição: &&= e ||=
Desde a primeira versão, o C# suporta sintaxes que combinam atribuições com outro operador. Isso inclui quase todos os operadores binários (ex.: +, -, &, etc) aguardando as avaliações de curto-circuito de operadores booleanos && e ||. A proposta dos operadores de atribuição &&= e ||= complementam essa lista.
Strings Textuais Interpoladas
Strings textuais começam com um @". Strings interpoladas utilizam $". Mas e se quisermos ambos, uma string textual interpolada? Usamos @$" ou $@". Atualmente um deles funciona, e o outro é um erro de compilação, qual é qual é difícil de lembrar.
Numa proposta modesta chamada string textual interpolada, a sintaxe será estendida para aceitar @$". Isso será interpretado exatamente da mesma forma que strings interpoladas textuais ($@"), para nunca termos que nos preocupar em voltar ao código depois.
Há algumas pequenas controvérsias sobre essa mudança, que alguns dizem desnecessária ou que poderia levar a inconsistências.
Permitir o 'using' corresponder estruturalmente ao 'IDisposable'
As interfaces têm um relacionamento estranho com o compilador C#. Geralmente não temos que implementar uma interface abstrata específica para utilizar as funcionalidades de uma linguagem; simplesmente temos que criar uma API pública na classe que referencia a interface abstrata.
O exemplo clássico é o foreach e IEnumerable. Se a classe tiver um método chamado GetEnumerator que retorna um objeto com uma propriedade Current e um método MoveNext, então ela pode usar o foreach. O tipo retornado não importa, o que permite classes como um List<T> implementar enumeradores mais rápidos. Isso é geralmente chamado de "correspondência estrutural".
Sob essa proposta, a declaração 'using' poderá suportar correspondência estrutural. De primeira não parece muito útil, pois você não espera que uma classe disposable não implemente IDisposable. No entanto, há um novo tipo chamado ref struct que não pode implementar interfaces, portanto não podem ser usadas com a declaração 'using' sem essa proposta.
Métodos de extensão com foreach e using
Prosseguindo na proposta anterior é a habilidade de adicionar o GetEnumerator ou o Dispose como métodos de extensão e fazê-los trabalhar respectivamente com 'foreach' e 'using'. Novamente, estamos falando de um recurso que será usado apenas em circunstâncias bem específicas. Por exemplo, podemos adicionar um método de extensão Dispose a um objeto COM de uma biblioteca de terceiros (que pode ser um bom lugar para chamar o Marshal.ReleaseComObject).
Esta não é uma proposta formal ainda e pode ser incorporada nas mudanças acima, na declaração 'using'.
Declarações 'using' Implícitas no Escopo
Atualmente, um 'using' só pode ser seguido por um escopo explícito (ex.: um par de chaves) ou outra instrução 'using'. Se essa proposta for aceita, então isso pode ser escrito também:
using var a = new MyDisposable();
using var b = new MyDisposable();
using var c = new MyDisposable();
Cada uma dessas variáveis será automaticamente descartada no fim do escopo corrente, na ordem inversa. Funcionalmente isso equivale a isso, mas menos verboso e sem um escopo novo.
using (var a = new MyDisposable())
using (var b = new MyDisposable())
using (var c = new MyDisposable())
{
// Some code
}
Essa mudança pode ser útil quando múltiplos objetos descartáveis são necessários, mas não são criados ao mesmo tempo. Podemos criar objetos descartáveis no meio de uma expressão e confiar que ele será descartado ao fim do escopo corrente.
var results = myExcelReader.ReadResults(using new MyExcelSheet(excelFilePath));
Uma crítica a essa proposta é que ela não é compatível com algumas instruções como o 'goto'.