Compartilhar via


Novidades no C# 13

O C# 13 inclui os novos recursos a seguir. Você pode experimentar esses recursos usando a versão mais recente do Visual Studio 2022 ou o SDK do .NET 9 :

A partir do Visual Studio 17.12, o C# 13 inclui a palavra-chave contextual field como um recurso de visualização.

O C# 13 tem suporte em .NET 9. Para obter mais informações, confira Controle de versão da linguagem C#.

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

Novos recursos são adicionados à página "Novidades no C#" quando estão disponíveis em versões de visualização pública. A seção conjunto de trabalho da página de status do recurso roslyn acompanha quando os recursos futuros são mesclados na ramificação principal.

Você encontra alterações interruptivas introduzidas no C# 13 em nosso artigo sobre alterações interruptivas.

Nota

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.

Coleções params

O modificador de params não se limita aos tipos de matriz. Agora você pode usar params com qualquer tipo de coleção reconhecido, incluindo System.Span<T>, System.ReadOnlySpan<T>e tipos que implementam System.Collections.Generic.IEnumerable<T> e têm um método Add. Além dos tipos concretos, as interfaces System.Collections.Generic.IEnumerable<T>, System.Collections.Generic.IReadOnlyCollection<T>, System.Collections.Generic.IReadOnlyList<T>, System.Collections.Generic.ICollection<T>e System.Collections.Generic.IList<T> também podem ser usadas.

Quando um tipo de interface é usado, o compilador sintetiza o armazenamento para os argumentos fornecidos. Saiba mais sobre a especificação do recurso para coleções params.

Por exemplo, as declarações de método podem declarar intervalos como parâmetros params:

public void Concat<T>(params ReadOnlySpan<T> items)
{
    for (int i = 0; i < items.Length; i++)
    {
        Console.Write(items[i]);
        Console.Write(" ");
    }
    Console.WriteLine();
}

Novo objeto de bloqueio

O runtime do .NET 9 inclui um novo tipo para sincronização de thread, o tipo System.Threading.Lock. Esse tipo fornece melhor sincronização de thread por meio de sua API. O método Lock.EnterScope() insere um escopo exclusivo. O ref struct retornado dá suporte ao padrão Dispose() para sair do escopo exclusivo.

A instrução C# lock reconhece se o alvo do bloqueio é um objeto Lock. Nesse caso, ele usa a API atualizada, em vez da API tradicional usando System.Threading.Monitor. O compilador também reconhece se você converter um objeto Lock em outro tipo e o código baseado em Monitor será gerado. Você pode ler mais na especificação de funcionalidade do novo objeto de bloqueio .

Esse recurso permite que você, ao alterar o tipo de objeto lock, obtenha os benefícios do novo tipo de biblioteca. Nenhum outro código precisa ser alterado.

Nova sequência de escape

Você pode usar \e como uma sequência de escape de literal de caractere para o caractere ESCAPE, U+001BUnicode. Anteriormente, você usava \u001b ou \x1b. Usar \x1b não foi recomendado porque se os próximos caracteres após 1b forem dígitos hexadecimal válidos, esses caracteres se tornarão parte da sequência de escape.

Tipo natural do grupo de métodos

Esse recurso faz pequenas otimizações para sobrecarregar a resolução envolvendo grupos de métodos. Um grupo de métodos é um método, juntamente com todas as suas sobrecargas com o mesmo nome. O comportamento anterior era que o compilador construísse o conjunto completo de métodos candidatos para um grupo de métodos. Se um tipo natural fosse necessário, o tipo natural era determinado a partir do conjunto completo de métodos candidatos.

O novo comportamento é podar o conjunto de métodos candidatos em cada escopo, removendo os métodos candidatos que não são aplicáveis. Normalmente, os métodos removidos são métodos genéricos com a aridade errada ou restrições que não são atendidas. O processo continuará para o próximo escopo externo somente se nenhum método candidato for encontrado. Esse processo segue mais de perto o algoritmo geral para resolução de sobrecarga. Se todos os métodos candidatos encontrados em um determinado escopo não corresponderem, o grupo de métodos não terá um tipo natural.

Você pode ler os detalhes das alterações na especificação da proposta.

Acesso implícito ao índice

O operador de índice "do final" implícito ^, agora é permitido em uma expressão de inicializador de objeto. Por exemplo, agora você pode inicializar uma matriz em um inicializador de objeto, conforme mostrado no seguinte código:

public class TimerRemaining
{
    public int[] buffer { get; set; } = new int[10];
}

var countdown = new TimerRemaining()
{
    buffer =
    {
        [^1] = 0,
        [^2] = 1,
        [^3] = 2,
        [^4] = 3,
        [^5] = 4,
        [^6] = 5,
        [^7] = 6,
        [^8] = 7,
        [^9] = 8,
        [^10] = 9
    }
};

A classe TimerRemaining inclui uma matriz de buffer inicializada em um comprimento de 10. O exemplo anterior atribui valores a essa matriz usando o operador de índice "do final" (^), criando efetivamente uma matriz que conta de 9 para 0.

Em versões antes do C# 13, o operador ^ não pode ser usado em um inicializador de objeto. Você precisa indexar os elementos da frente.

ref e unsafe em iteradores e métodos de async

Esse recurso e os dois recursos a seguir permitem que ref struct tipos usem novos constructos. Você não os usará a menos que escreva seus próprios tipos de ref struct. É mais provável que você veja um benefício indireto à medida que System.Span<T> e System.ReadOnlySpan<T> obtêm mais funcionalidade.

Antes do C# 13, os métodos de iterador (métodos que usam yield return) e métodos async não podiam declarar variáveis de ref locais nem poderiam ter um contexto unsafe.

Na versão C# 13, métodos async podem declarar ref variáveis locais, ou variáveis locais de tipo ref struct. No entanto, essas variáveis não podem ser acessadas em um limite await. Eles também não podem ser acessados em um limite yield return.

Essa restrição descontraída permite que o compilador autorize o uso seguro de variáveis locais ref e tipos ref struct em mais locais. Você pode usar com segurança tipos como System.ReadOnlySpan<T> nesses métodos. O compilador informa se você viola as regras de segurança.

Da mesma forma, o C# 13 permite contextos unsafe em métodos de iterador. Entretanto, todas as instruções yield return e yield break devem estar em contextos seguros.

allows ref struct

Antes do C# 13, ref struct tipos não podiam ser declarados como o argumento de tipo para um tipo ou método genérico. Agora, declarações de tipo genérico podem adicionar uma anti-restrição, allows ref struct. Essa antirrestringência declara que o argumento de tipo fornecido para esse parâmetro de tipo pode ser do tipo ref struct. O compilador impõe regras de segurança ref em todas as instâncias desse parâmetro de tipo.

Por exemplo, você pode declarar um tipo genérico como o seguinte código:

public class C<T> where T : allows ref struct
{
    // Use T as a ref struct:
    public void M(scoped T p)
    {
        // The parameter p must follow ref safety rules
    }
}

Isso permite que tipos como System.Span<T> e System.ReadOnlySpan<T> sejam usados com algoritmos genéricos, quando aplicável. Você pode saber mais nas atualizações para where e no artigo do guia de programação sobre restrições genéricas .

Interfaces ref struct

Antes do C# 13, os tipos de ref struct não podiam implementar interfaces. A partir do C# 13, eles podem. Você pode declarar que um tipo de ref struct implementa uma interface. Mas para garantir a segurança das regras de ref, um tipo ref struct não pode ser convertido em um tipo de interface. Essa conversão é de boxing e pode violar a segurança de ref. Declarações de método de interface explícitas em ref struct só podem ser acessadas através de um parâmetro de tipo, que seja allows ref struct. Além disso, os tipos ref struct devem implementar todos os métodos declarados em uma interface, incluindo esses métodos com uma implementação padrão.

Saiba mais nas atualizações sobre ref struct tipos e a adição da restrição genérica allows ref struct.

Membros com mais parcialidade

Você pode declarar propriedades partial e indexadores partial no C# 13. As propriedades parciais e os indexadores geralmente seguem as mesmas regras que os métodos partial: você cria uma declaração para declarar e uma declaração para implementar. As assinaturas das duas declarações devem corresponder. Uma restrição é que você não pode usar uma declaração de propriedade automática para implementar uma propriedade parcial. As propriedades que não definem um corpo são consideradas a declaração correspondente.

public partial class C
{
    // Declaring declaration
    public partial string Name { get; set; }
}

public partial class C
{
    // implementation declaration:
    private string _name;
    public partial string Name
    {
        get => _name;
        set => _name = value;
    }
}

Saiba mais no artigo sobre membros parciais.

Prioridade de resolução de sobrecarga

No C# 13, o compilador reconhece a OverloadResolutionPriorityAttribute para preferir uma sobrecarga em vez de outra. Os autores da biblioteca podem usar esse atributo para garantir que uma sobrecarga nova e melhor seja preferida em vez de uma sobrecarga existente. Por exemplo, você pode adicionar uma nova sobrecarga que seja mais eficiente. Você não deseja interromper o código existente que usa sua biblioteca, mas deseja que os usuários atualizem para a nova versão quando eles recompilarem. Você pode usar Prioridade na resolução de sobrecarga para informar ao compilador qual sobrecarga deve ser priorizada. As sobrecargas com a prioridade mais alta são preferenciais.

Esse recurso destina-se aos autores da biblioteca para evitar ambiguidade ao adicionar novas sobrecargas. Os autores da biblioteca devem ter cuidado com esse atributo para evitar confusão.

A palavra-chave field

A palavra-chave contextual field está em C# 13 como um recurso de visualização. O token field acessa o campo de backup sintetizado do compilador em um acessador de propriedade. Ele permite que você escreva um corpo acessador sem declarar um campo de backup explícito em sua declaração de tipo. Você pode declarar um corpo para um ou ambos os acessadores de uma propriedade de campo.

O recurso field é lançado como um recurso em versão preliminar. Queremos aprender com suas experiências usando-a. Há uma possível alteração incompatível ou confusão ao ler código em tipos que também incluem um campo chamado field. Você pode usar @field ou this.field para desambiguar entre a palavra-chave field e o identificador.

Importante

A palavra-chave field é um recurso de visualização no C# 13. Você deve usar o .NET 9 e definir seu elemento <LangVersion> para preview no arquivo de projeto para usar a palavra-chave contextual field.

Você deve ter cuidado ao usar o recurso de palavra-chave field em uma classe que tenha um campo chamado field. A nova palavra-chave field oculta um campo chamado field dentro do escopo de um acessador de propriedade. Você pode alterar o nome da variável field ou usar o token @ para referenciar o identificador field como @field. Para saber mais, leia a especificação do recurso para a palavra-chave field.

Se você testar esse recurso e receber feedback, adicione-o ao problema de recurso no repositório csharplang.

Consulte também