O que há de novo no C# 12
O C# 12 inclui os seguintes novos recursos. Você pode experimentar esses recursos usando a versão mais recente do Visual Studio 2022 ou o SDK do .NET 8.
Construtores primários - Introduzido no Visual Studio 2022 versão 17.6 Preview 2.
Expressões de coleção - Introduzido no Visual Studio 2022 versão 17.7 Preview 5.
Matrizes embutidas - Introduzidas no Visual Studio 2022 versão 17.7 Preview 3.
Parâmetros opcionais em expressões lambda - Introduzido no Visual Studio 2022 versão 17.5 Preview 2.
ref readonly
parâmetros - Introduzido no Visual Studio 2022 versão 17.8 Preview 2.Alias any type - Introduzido no Visual Studio 2022 versão 17.6 Preview 3.
Atributo experimental - Introduzido no Visual Studio 2022 versão 17.7 Preview 3.
Recurso Interceptors - Preview Introduzido no Visual Studio 2022 versão 17.7 Preview 3.
O C# 12 é suportado no .NET 8. Para obter mais informações, consulte Versionamento de linguagem C#.
Você pode baixar o SDK mais recente do .NET 8 na página de downloads do .NET. Você também pode baixar o Visual Studio 2022, que inclui o SDK do .NET 8.
Nota
Estamos interessados nos seus comentários sobre estas funcionalidades. Se você encontrar problemas com qualquer um desses novos recursos, crie um novo problema no repositório dotnet/roslyn .
Construtores primários
Agora você pode criar construtores primários em qualquer class
e struct
. Os construtores primários não estão mais restritos aos record
tipos. Os parâmetros primários do construtor estão no escopo de todo o corpo da classe. Para garantir que todos os parâmetros do construtor primário sejam definitivamente atribuídos, todos os construtores explicitamente declarados devem chamar o construtor primário usando this()
sintaxe. Adicionar um construtor primário a um class
impede que o compilador declare um construtor implícito sem parâmetros. Em um struct
, o construtor implícito sem parâmetros inicializa todos os campos, incluindo os parâmetros primários do construtor para o padrão de 0 bits.
O compilador gera propriedades públicas para parâmetros primários do construtor somente em record
tipos, ou record class
record struct
tipos. Classes e estruturas que não são de registro nem sempre desejam esse comportamento para parâmetros primários do construtor.
Você pode aprender mais sobre construtores primários no tutorial para explorar construtores primários e no artigo sobre construtores de instância.
Expressões da coleção
As expressões de coleção introduzem uma nova sintaxe para criar valores de coleção comuns. Inserir outras coleções nesses valores é possível usando um operador ..
de spread .
Vários tipos semelhantes a coleções podem ser criados sem a necessidade de suporte BCL externo. Estes tipos são:
- Tipos de matriz, como
int[]
. - System.Span<T> e System.ReadOnlySpan<T>.
- Tipos que suportam inicializadores de coleção, como System.Collections.Generic.List<T>.
Os exemplos a seguir mostram usos de expressões de coleção:
// Create an array:
int[] a = [1, 2, 3, 4, 5, 6, 7, 8];
// Create a list:
List<string> b = ["one", "two", "three"];
// Create a span
Span<char> c = ['a', 'b', 'c', 'd', 'e', 'f', 'h', 'i'];
// Create a jagged 2D array:
int[][] twoD = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
// Create a jagged 2D array from variables:
int[] row0 = [1, 2, 3];
int[] row1 = [4, 5, 6];
int[] row2 = [7, 8, 9];
int[][] twoDFromVariables = [row0, row1, row2];
O operador spread, em uma expressão de coleção, ..
substitui seu argumento pelos elementos dessa coleção. O argumento deve ser um tipo de coleção. Os exemplos a seguir mostram como o operador de spread funciona:
int[] row0 = [1, 2, 3];
int[] row1 = [4, 5, 6];
int[] row2 = [7, 8, 9];
int[] single = [.. row0, .. row1, .. row2];
foreach (var element in single)
{
Console.Write($"{element}, ");
}
// output:
// 1, 2, 3, 4, 5, 6, 7, 8, 9,
O operando de um operador spread é uma expressão que pode ser enumerada. O operador spread avalia cada elemento da expressão de enumerações.
Você pode usar expressões de coleção em qualquer lugar que precise de uma coleção de elementos. Eles podem especificar o valor inicial de uma coleção ou ser passados como argumentos para métodos que usam tipos de coleção. Você pode saber mais sobre expressões de coleção no artigo de referência de linguagem sobre expressões de coleção ou na especificação de recurso.
ref readonly
Parâmetros
O C# adicionou in
parâmetros como uma maneira de passar referências somente leitura. in
Os parâmetros permitem variáveis e valores, e podem ser usados sem qualquer anotação em argumentos.
A adição de ref readonly
parâmetros permite mais clareza para APIs que podem estar usando ref
parâmetros ou in
parâmetros:
- As APIs criadas antes
in
de serem introduzidas podem ser usadasref
mesmo que o argumento não seja modificado. Essas APIs podem ser atualizadas comref readonly
o . Não será uma alteração de quebra para chamadores, como seria se oref
parâmetro fosse alterado parain
. Um exemplo é System.Runtime.InteropServices.Marshal.QueryInterface. - APIs que usam um
in
parâmetro, mas logicamente exigem uma variável. Uma expressão de valor não funciona. Um exemplo é System.ReadOnlySpan<T>.ReadOnlySpan<T>(T). - APIs que usam
ref
porque exigem uma variável, mas não mutam essa variável. Um exemplo é System.Runtime.CompilerServices.Unsafe.IsNullRef.
Para saber mais sobre ref readonly
parâmetros, consulte o artigo sobre modificadores de parâmetros na referência de idioma ou a especificação de recurso de parâmetros ref readonly.
Parâmetros lambda padrão
Agora você pode definir valores padrão para parâmetros em expressões lambda. A sintaxe e as regras são as mesmas que adicionar valores padrão para argumentos a qualquer método ou função local.
Você pode saber mais sobre parâmetros padrão em expressões lambda no artigo sobre expressões lambda.
Alias qualquer tipo
Você pode usar a using
diretiva alias para alias de qualquer tipo, não apenas tipos nomeados. Isso significa que você pode criar aliases semânticos para tipos de tupla, tipos de matriz, tipos de ponteiro ou outros tipos inseguros. Para obter mais informações, consulte a especificação do recurso.
Matrizes em linha
As matrizes embutidas são usadas pela equipe de tempo de execução e outros autores de bibliotecas para melhorar o desempenho em seus aplicativos. As matrizes embutidas permitem que um desenvolvedor crie uma matriz de tamanho fixo em um struct
tipo. Uma struct com um buffer embutido deve fornecer características de desempenho semelhantes a um buffer de tamanho fixo inseguro. Você provavelmente não declarará suas próprias matrizes embutidas, mas as usará de forma transparente quando forem expostas como System.Span<T> ou System.ReadOnlySpan<T> objetos de APIs de tempo de execução.
Uma matriz embutida é declarada semelhante à seguinte struct
:
[System.Runtime.CompilerServices.InlineArray(10)]
public struct Buffer
{
private int _element0;
}
Você os usa como qualquer outra matriz:
var buffer = new Buffer();
for (int i = 0; i < 10; i++)
{
buffer[i] = i;
}
foreach (var i in buffer)
{
Console.WriteLine(i);
}
A diferença é que o compilador pode tirar proveito de informações conhecidas sobre uma matriz embutida. Você provavelmente consumiria matrizes embutidas como faria com qualquer outra matriz. Para obter mais informações sobre como declarar matrizes embutidas, consulte a referência de idioma em struct
tipos.
Atributo experimental
Tipos, métodos ou montagens podem ser marcados com o System.Diagnostics.CodeAnalysis.ExperimentalAttribute para indicar um recurso experimental. O compilador emite um aviso se você acessar um método ou tipo anotado com o ExperimentalAttribute. Todos os tipos incluídos em um assembly marcado com o Experimental
atributo são experimentais. Você pode ler mais no artigo sobre Atributos gerais lidos pelo compilador ou na especificação do recurso.
Intercetores
Aviso
Os intercetores são um recurso experimental, disponível no modo de visualização com C# 12. O recurso pode estar sujeito a alterações ou remoção em uma versão futura. Portanto, não é recomendado para aplicações de produção ou lançadas.
Para usar intercetores, o projeto do usuário deve especificar a propriedade <InterceptorsPreviewNamespaces>
. Esta é uma lista de namespaces que podem conter intercetadores.
Por exemplo: <InterceptorsPreviewNamespaces>$(InterceptorsPreviewNamespaces);Microsoft.AspNetCore.Http.Generated;MyLibrary.Generated</InterceptorsPreviewNamespaces>
Um intercetador é um método que pode substituir declarativamente uma chamada para um método interceptável por uma chamada para si mesmo em tempo de compilação. Essa substituição ocorre fazendo com que o intercetor declare os locais de origem das chamadas que interceta. Os intercetores fornecem uma facilidade limitada para alterar a semântica do código existente, adicionando novo código a uma compilação, por exemplo, em um gerador de código-fonte.
Você usa um intercetor como parte de um gerador de código-fonte para modificar, em vez de adicionar código a uma compilação de código-fonte existente. O gerador de origem substitui chamadas para um método interceptável por uma chamada para o método intercetor .
Se você estiver interessado em experimentar intercetadores, você pode saber mais lendo a especificação do recurso. Se você usar o recurso, certifique-se de manter-se atualizado com quaisquer alterações na especificação do recurso para esse recurso experimental. Se o recurso for finalizado, adicionaremos mais orientações neste site.