Novidades do C# 10

O C# 10 adiciona os seguintes recursos e aprimoramentos à linguagem C#:

O C# 10 tem suporte no .NET 6. Para obter mais informações, confira Controle de versão da linguagem C#.

Você pode baixar o SDK mais recente do .NET 6 na página de downloads do .NET. Você também pode baixar o Visual Studio 2022, que inclui o SDK do .NET 6.

Observação

Estamos interessados em seus comentários sobre esses recursos. Se você encontrar problemas com qualquer um desses novos recursos, crie um problema no repositório dotnet/roslyn.

Structs de registro

Você pode declarar registros de tipo de valor usando as declarações record struct ou readonly record struct. Agora você pode esclarecer que record é um tipo de referência com a declaração record class.

Aprimoramentos de tipos de estrutura

O C# 10 apresenta as seguintes melhorias relacionadas aos tipos de estrutura:

  • Você pode declarar um construtor sem parâmetros de instância em um tipo de estrutura e inicializar um campo ou propriedade de instância na declaração. Para obter mais informações, consulte a seção Inicialização de struct e valores padrão do artigo Tipos de estrutura.
  • Um operando à esquerda da expressão with pode ser de qualquer tipo de estrutura ou um tipo anônimo (referência).

Manipuladores de cadeia de caracteres interpolada

Você pode criar um tipo que compila a cadeia de caracteres resultante de uma expressão de cadeia de caracteres interpolada. As bibliotecas .NET usam esse recurso em muitas APIs. Você pode criar um seguindo este tutorial.

Diretivas using globais

Você pode adicionar o modificador global a qualquer diretiva de uso para instruir o compilador ao qual a diretiva se aplica a todos os arquivos de origem na compilação. Normalmente, são todos os arquivos de origem em um projeto.

Declaração de namespace com escopo de arquivo

Você pode usar uma nova forma da declaração namespace para declarar que todas as seguintes declarações são membros do namespace declarado:

namespace MyNamespace;

Essa nova sintaxe salva espaço horizontal e vertical para declarações namespace.

Padrões de propriedade estendida

A partir do C# 10, você pode referenciar propriedades aninhadas ou campos dentro de um padrão de propriedade. Por exemplo, um padrão do formulário

{ Prop1.Prop2: pattern }

é válido em C# 10 e posterior e equivalente a

{ Prop1: { Prop2: pattern } }

válido em C# 8.0 e posterior.

Para obter mais informações, confira a nota de proposta de recursos de Padrões de propriedade estendida. Para obter mais informações sobre um padrão de propriedade, confira a seção Padrão de propriedade do artigo Padrões.

Aprimoramentos da expressão lambda

O C# 10 inclui muitas melhorias na forma como as expressões lambda são tratadas:

  • As expressões Lambda podem ter um tipo natural, em que o compilador pode inferir um tipo delegado da expressão lambda ou do grupo de métodos.
  • As expressões Lambda podem declarar um tipo de retorno quando o compilador não pode inferi-lo.
  • Os atributos podem ser aplicados a expressões lambda.

Esses recursos tornam as expressões lambda mais semelhantes a métodos e funções locais. Elas facilitam o uso de expressões lambda sem declarar uma variável de um tipo delegado e funcionam mais perfeitamente com as novas APIs mínimas de ASP.NET Core.

Cadeias de caracteres interpoladas constantes

No C# 10, as cadeias de caracteres const poderão ser inicializadas usando a interpolação de cadeia de caracteres se todos os espaços reservados forem cadeias de caracteres constantes. A interpolação de cadeia de caracteres pode criar cadeias de caracteres constantes mais legíveis à medida que elas são criadas e usadas no aplicativo. As expressões de espaço reservado não podem ser constantes numéricas porque essas constantes são convertidas em cadeias de caracteres em tempo de execução. A cultura atual pode afetar a representação de cadeia de caracteres. Saiba mais na referência de linguagem sobre expressõesconst.

Tipos de registro podem selar ToString

No C# 10, você pode adicionar o modificador sealed ao substituir ToString em um tipo de registro. Selar o método ToString impede que o compilador sintetize um método ToString para qualquer tipo de registro derivado. Um sealedToString garante que todos os tipos de registro derivados usem o método ToString definido em um tipo de registro base comum. Você pode saber mais sobre esse recurso no artigo sobre registros.

Atribuição e declaração na mesma desconstrução

Essa alteração remove uma restrição de versões anteriores do C#. Anteriormente, uma desconstrução poderia atribuir todos os valores a variáveis existentes ou inicializar variáveis recém-declaradas:

// Initialization:
(int x, int y) = point;

// assignment:
int x1 = 0;
int y1 = 0;
(x1, y1) = point;

O C# 10 remove essa restrição:

int x = 0;
(x, int y) = point;

Atribuição definitiva aprimorada

Antes do C# 10, havia muitos cenários em que a atribuição definitiva e a análise de estado nulo produziam avisos que eram falsos positivos. Geralmente, elas envolviam comparações com constantes boolianas, acesso a uma variável somente nas instruções true ou false em uma instrução if e expressões de associação nulas. Esses exemplos geraram avisos em versões anteriores do C#, mas não no C# 10:

string representation = "N/A";
if ((c != null && c.GetDependentValue(out object obj)) == true)
{
   representation = obj.ToString(); // undesired error
}

// Or, using ?.
if (c?.GetDependentValue(out object obj) == true)
{
   representation = obj.ToString(); // undesired error
}

// Or, using ??
if (c?.GetDependentValue(out object obj) ?? false)
{
   representation = obj.ToString(); // undesired error
}

O principal impacto dessa melhoria é que os avisos para atribuição definitiva e análise de estado nulo são mais precisos.

Permitir atributo AsyncMethodBuilder em métodos

No C# 10 e posterior, você pode especificar um construtor de métodos assíncrono diferente para um método único, além de especificar o tipo de construtor de métodos para todos os métodos que retornam um determinado tipo de tarefa. Um construtor de métodos assíncrono personalizado permite cenários avançados de ajuste de desempenho em que um determinado método pode se beneficiar de um construtor personalizado.

Para saber mais, confira a seção sobre AsyncMethodBuilder no artigo que aborda atributos lidos pelo compilador.

Diagnóstico de atributo CallerArgumentExpression

Você pode usar o parâmetro System.Runtime.CompilerServices.CallerArgumentExpressionAttribute para especificar um parâmetro que o compilador substitui pela representação de texto de outro argumento. Esse recurso permite que as bibliotecas criem diagnósticos mais específicos. O código a seguir testa uma condição. Se a condição for falsa, a mensagem de exceção conterá a representação de texto do argumento passado para condition:

public static void Validate(bool condition, [CallerArgumentExpression("condition")] string? message=null)
{
    if (!condition)
    {
        throw new InvalidOperationException($"Argument failed validation: <{message}>");
    }
}

Você pode saber mais sobre esse recurso no artigo sobre Atributos de informações do chamador na seção de referência de linguagem.

Pragma de #line avançado

O C# 10 dá suporte a um novo formato para o pragma #line. Você provavelmente não usará o novo formato, mas verá os respectivos. Os aprimoramentos permitem uma saída mais refinada em DSLs (linguagens específicas do domínio), como Razor. O mecanismo Razor usa essas melhorias para aprimorar a experiência de depuração. Você encontrará depuradores que podem realçar a fonte Razor com mais precisão. Para saber mais sobre a nova sintaxe, confira o artigo sobre Diretivas de pré-processador na referência de linguagem. Você também pode ler a especificação de recurso para exemplos baseados em Razor.