Novidades do C# 11

Os seguintes recursos foram adicionados em C# 11:

O C# 11 tem suporte no .NET 7. Para obter mais informações, consulte Controle de versão da linguagem C#.

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

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.

Atributos genéricos

Você pode declarar uma classe genérica cuja classe base é System.Attribute. Este recurso fornece uma sintaxe mais conveniente para atributos que exigem um parâmetro System.Type. Anteriormente, você precisaria criar um atributo com um Type como parâmetro de construtor:

// Before C# 11:
public class TypeAttribute : Attribute
{
   public TypeAttribute(Type t) => ParamType = t;

   public Type ParamType { get; }
}

E para aplicar o atributo, você usa o operador typeof:

[TypeAttribute(typeof(string))]
public string Method() => default;

Usando esse novo recurso, você pode criar um atributo genérico em vez disso:

// C# 11 feature:
public class GenericAttribute<T> : Attribute { }

Em seguida, especifique o tipo de parâmetro para usar o atributo:

[GenericAttribute<string>()]
public string Method() => default;

Você deve fornecer todos os parâmetros de tipo ao aplicar o atributo. Em outras palavras, o tipo genérico deve ser totalmente construído. No exemplo acima, os parênteses vazios (( e )) podem ser omitidos, pois o atributo não tem argumentos.

public class GenericType<T>
{
   [GenericAttribute<T>()] // Not allowed! generic attributes must be fully constructed types.
   public string Method() => default;
}

Os argumentos de tipo devem atender às mesmas restrições do operador typeof. Tipos que exigem anotações de metadados não são permitidos. Por exemplo, os seguintes tipos não são permitidos como o parâmetro de tipo:

  • dynamic
  • string? (ou qualquer tipo de referência anulável)
  • (int X, int Y) (ou qualquer outro tipo de tupla usando a sintaxe de tupla C#).

Esses tipos não são representados diretamente em metadados. Elas incluem anotações que descrevem o tipo. Em todos os casos, você pode usar o tipo subjacente em vez disso:

  • object para dynamic.
  • string em vez destring?.
  • ValueTuple<int, int> em vez de(int X, int Y).

Suporte matemático genérico

Há vários recursos de linguagem que permitem suporte matemático genérico:

  • Membros static virtual em interfaces
  • operadores verificados definidos pelo usuário
  • operadores de deslocamento flexíveis
  • operador de deslocamento para a direita sem sinal

Você pode adicionar membros static abstract ou static virtual em interfaces para definir interfaces que incluam operadores sobrecarregados, outros membros estáticos e propriedades estáticas. O cenário principal para esse recurso é usar operadores matemáticos em tipos genéricos. Por exemplo, você pode implementar a interface System.IAdditionOperators<TSelf, TOther, TResult> em um tipo que implementa o operator +. Outras interfaces definem outras operações matemáticas ou valores bem definidos. Você pode aprender sobre a nova sintaxe no artigo sobre interfaces. Interfaces que incluem métodos static virtual normalmente são interfaces genéricas. Além disso, a maioria declarará uma restrição de que o parâmetro de tipo implemente a interface declarada.

Você pode saber mais e experimentar o recurso no tutorial Explorar membros da interface abstrata estática ou na postagem no blog sobre Versão prévia do recurso no .NET 6 – matemática genérica.

A matemática genérica criou outros requisitos na linguagem.

  • Operador de deslocamento para a direita sem sinal: antes do C# 11, para forçar um deslocamento para a direita sem sinal, você precisaria converter qualquer tipo inteiro com sinal em um tipo sem sinal, executar a mudança e, em seguida, converter o resultado de volta para um tipo com sinal. A partir do C# 11, você pode usar o >>>, o operador de deslocamento sem sinal.
  • Requisitos de operador de deslocamento para a direita sem sinal: o C# 11 remove o requisito de que o segundo operando deve ser um int ou implicitamente conversível para int. Essa alteração permite que os tipos que implementam interfaces matemáticas genéricas sejam usados nesses locais.
  • operadores marcados e desmarcados definidos pelo usuário: os desenvolvedores agora podem definir operadores aritméticos checked e unchecked. O compilador gera chamadas para a variante correta com base no contexto atual. Você pode ler mais sobre operadores checked no artigo sobre operadores aritméticos.

Numérico IntPtr e UIntPtr

Os tipos nint e nuint agora têm como alias System.IntPtr e System.UIntPtr, respectivamente.

Novas linhas em interpolações de cadeia de caracteres

O texto dentro dos caracteres { e } para uma interpolação de cadeia de caracteres agora pode abranger várias linhas. O texto entre os marcadores { e } é analisado como C#. Qualquer C# legal, inclusive novas linhas, é permitido. Esse recurso facilita a leitura de interpolações de cadeia de caracteres que usam expressões C# mais longas, como expressões switch de padrões correspondentes ou consultas LINQ.

Você pode saber mais sobre o recurso de novas linhas no artigo de interpolações de cadeia de caracteres na referência de linguagem.

Padrões de lista

Padrões de lista estendem a correspondência de padrões para corresponder a sequências de elementos em uma lista ou em uma matriz. Por exemplo, sequence is [1, 2, 3] é true quando a sequence é um matriz ou uma lista de três inteiros (1, 2 e 3). Você pode fazer a correspondência de elementos usando qualquer padrão, inclusive uma constante, tipo, propriedade e padrões relacionais. O padrão de descarte (_) corresponde a qualquer elemento único e o novo padrão de intervalo (..) corresponde a qualquer sequência de zero ou mais elementos.

Você pode saber mais detalhes sobre padrões de lista no artigo de padrões correspondentes na referência de linguagem.

Conversão aprimorada do grupo de métodos para delegado

O padrão C# em conversões de grupo de métodos agora inclui o seguinte item:

  • A conversão é permitida (mas não é necessária) para usar uma instância delegada existente que já contenha essas referências.

As versões anteriores do padrão proibiam o compilador de reutilizar o objeto delegado criado para uma conversão de grupo de métodos. O compilador C# 11 armazena em cache o objeto delegado criado de uma conversão de grupo de métodos e reutiliza esse único objeto delegado. Esse recurso foi disponibilizado pela primeira vez no Visual Studio 2022 versão 17.2 como uma versão prévia do recurso e no .NET 7 Versão Prévia 2.

Literais de cadeia de caracteres bruta

Literais de cadeia de caracteres bruta são um novo formato para literais de cadeia de caracteres. Literais de cadeia de caracteres bruta podem conter texto arbitrário, incluindo espaços em branco, novas linhas, aspas inseridas e outros caracteres especiais sem a necessidade de sequências de escape. Um literal de cadeia de caracteres bruta começa com pelo menos três caracteres de aspas duplas ("""). Ele termina com o mesmo número de caracteres de aspas duplas. Normalmente, um literal de cadeia de caracteres bruta usa três aspas duplas em uma única linha para iniciar a cadeia de caracteres e três aspas duplas em uma linha separada para terminar a cadeia de caracteres. As novas linhas que seguem as aspas de abertura e precedem as aspas de fechamento não estão incluídas no conteúdo final:

string longMessage = """
    This is a long message.
    It has several lines.
        Some are indented
                more than others.
    Some should start at the first column.
    Some have "quoted text" in them.
    """;

Qualquer espaço em branco à esquerda das aspas duplas de fechamento será removido do literal da cadeia de caracteres. Os literais da cadeia de caracteres bruta podem ser combinados com a interpolação de cadeia de caracteres para incluir chaves no texto de saída. Vários caracteres $ indicam quantas chaves consecutivas iniciam e terminam a interpolação:

var location = $$"""
   You are at {{{Longitude}}, {{Latitude}}}
   """;

O exemplo anterior especifica que duas chaves iniciam e terminam uma interpolação. A terceira chave de abertura e de fechamento repetidas são incluídas na cadeia de caracteres de saída.

Você pode saber mais sobre literais de cadeia de caracteres bruta no artigo sobre cadeias de caracteres no guia de programação e nos artigos de referência de linguagem sobre literais de cadeia de caracteres e cadeias de caracteres interpoladas.

Structs de padrão automático

O compilador C# 11 garante que todos os campos de um tipo struct sejam inicializados para seu valor padrão como parte da execução de um construtor. Essa alteração significa que qualquer campo ou propriedade automática não inicializados por um construtor são inicializados automaticamente pelo compilador. Os structs em que o construtor não atribui definitivamente todos os campos agora são compilados, e todos os campos não inicializados explicitamente são definidos para o valor padrão. Você pode ler mais sobre como essa alteração afeta a inicialização de structs no artigo sobre structs.

Correspondência de padrão Span<char> e ReadOnlySpan<char> em uma constante string

Você conseguiu testar se um string tinha um valor constante específico usando padrões correspondentes para várias versões. Agora você pode usar a mesma lógica de padrões correspondentes com variáveis que são Span<char> ou ReadOnlySpan<char>.

Escopo nameof estendido

Nomes de parâmetros de tipo e nomes de parâmetro agora estão no escopo quando usados em uma expressão nameof em uma declaração de atributo nesse método. Essa funcionalidade significa que você pode usar o operador nameof para especificar o nome de um parâmetro de método em um atributo na declaração de método ou parâmetro. Esse recurso costuma ser útil para adicionar atributos para análise anulável.

Cadeia de caracteres UTF-8 literais

Você pode especificar o sufixo u8 em um literal de cadeia de caracteres para especificar a codificação de caracteres UTF-8. Se o aplicativo precisar de cadeias de caracteres UTF-8, para constantes de cadeia de caracteres HTTP ou protocolos de texto semelhantes, você pode usar esse recurso para simplificar a criação de cadeias de caracteres UTF-8.

Você pode saber mais sobre literais de cadeia de caracteres UTF-8 na seção literal de cadeia de caracteres do artigo sobre tipos de referência internos.

Membros necessários

Você pode adicionar o modificador required a propriedades e campos para impor construtores e chamadores para inicializar esses valores. O System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute pode ser adicionado aos construtores para informar ao compilador que um construtor inicializa todos os membros necessários.

Para obter mais informações sobre os membros necessários, consulte a seção somente init do artigo de propriedades.

Campos ref e variáveis ref scoped

Você pode declarar campos ref dentro de uma classe ref struct. Isso dá suporte a tipos como System.Span<T> sem atributos especiais ou tipos internos ocultos.

Você pode adicionar o modificador scoped a qualquer declaração ref. Isso limita o escopo para o qual a referência pode escapar.

Tipos de locais de arquivo

A partir do C# 11, você pode usar o modificador de acesso file para criar um tipo cuja visibilidade está no escopo do arquivo de origem no qual ele é declarado. Esse recurso ajuda os autores do gerador de origem a evitar colisões de nomenclatura. Você pode saber mais sobre esse recurso no artigo sobre tipos com escopo de arquivo na referência de linguagem.

Confira também