Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Este documento lista alterações interruptivas conhecidas no Roslyn após a versão geral do .NET 6 (SDK do .NET versão 6.0.100) até a versão geral do .NET 7 (SDK do .NET versão 7.0.100).
Todas as variáveis locais de tipos restritivos não são permitidas em métodos assíncronos
Introduzido no Visual Studio 2022 versão 17.6p1
Variáveis locais de tipos restritivos não são permitidas em métodos assíncronos. Mas em versões anteriores, o compilador não percebeu alguns locais declarados implicitamente. Por exemplo, em instruções ou desconstruções foreach
ou using
.
Agora, essas variáveis locais declaradas implicitamente não são mais permitidas.
ref struct RefStruct { public void Dispose() { } }
public class C
{
public async Task M()
{
RefStruct local = default; // disallowed
using (default(RefStruct)) { } // now disallowed too ("error CS9104: A using statement resource of this type cannot be used in async methods or async lambda expressions")
}
}
Consulte https://github.com/dotnet/roslyn/pull/66264
Os ponteiros devem estar sempre em contextos não seguros.
Introduzido no Visual Studio 2022 versão 17.6
Em SDKs anteriores, o compilador ocasionalmente permitia locais em que ponteiros poderiam ser referenciados, sem marcar explicitamente esse local como não seguro.
Agora, o unsafe
modificador deve estar presente.
Por exemplo, using Alias = List<int*[]>;
deve ser alterado para using unsafe Alias = List<int*[]>;
para ser legal.
Um uso como void Method(Alias a) ...
deve ser alterado para unsafe void Method(Alias a) ...
.
A regra é incondicional, exceto para using
declarações de alias (que não permitiam um unsafe
modificador antes do C# 12).
Portanto, para using
declarações, a regra só entrará em vigor se a versão do idioma for escolhida como C# 12 ou superior.
System.TypedReference considerado gerenciado
Introduzido no Visual Studio 2022 versão 17.6
A partir de agora, o tipo System.TypedReference
é considerado gerenciado.
unsafe
{
TypedReference* r = null; // warning: This takes the address of, gets the size of, or declares a pointer to a managed type
var a = stackalloc TypedReference[1]; // error: Cannot take the address of, get the size of, or declare a pointer to a managed type
}
Os erros de segurança de referência não afetam a conversão da expressão lambda para delegado
Introduzido no Visual Studio 2022 versão 17.5
Os erros de segurança de referência relatados em um corpo lambda não mais influenciam se a expressão lambda é conversível para um tipo delegado. Essa alteração pode afetar a resolução de sobrecarga.
No exemplo a seguir, a chamada de M(x => ...)
é ambígua com o Visual Studio 17.5 porque tanto M(D1)
quanto M(D2)
agora são considerados aplicáveis, mesmo que a chamada para F(ref x, ref y)
dentro do corpo lambda resulte em segurança de ref com M(D1)
(veja os exemplos em d1
e d2
para comparação). Anteriormente, a chamada estava inequivocamente vinculada a M(D2)
, pois a sobrecarga M(D1)
era considerada não aplicável.
using System;
ref struct R { }
delegate R D1(R r);
delegate object D2(object o);
class Program
{
static void M(D1 d1) { }
static void M(D2 d2) { }
static void F(ref R x, ref Span<int> y) { }
static void F(ref object x, ref Span<int> y) { }
static void Main()
{
// error CS0121: ambiguous between: 'M(D1)' and 'M(D2)'
M(x =>
{
Span<int> y = stackalloc int[1];
F(ref x, ref y);
return x;
});
D1 d1 = x1 =>
{
Span<int> y1 = stackalloc int[1];
F(ref x1, ref y1); // error CS8352: 'y2' may expose referenced variables
return x1;
};
D2 d2 = x2 =>
{
Span<int> y2 = stackalloc int[1];
F(ref x2, ref y2); // ok: F(ref object x, ref Span<int> y)
return x2;
};
}
}
Para solucionar as alterações na resolução de sobrecarga, use tipos explícitos para os parâmetros lambda ou de delegate.
// ok: M(D2)
M((object x) =>
{
Span<int> y = stackalloc int[1];
F(ref x, ref y); // ok: F(ref object x, ref Span<int> y)
return x;
});
Interpolações de cadeias de caracteres brutas no início da linha.
Introduzido no Visual Studio 2022 versão 17.5
No SDK do .NET 7.0.100 ou anterior, o seguinte foi erroneamente permitido:
var x = $"""
Hello
{1 + 1}
World
""";
Isso violou a regra de que o conteúdo das linhas (incluindo onde uma interpolação é iniciada) deve começar com o mesmo espaço em branco que a linha final """;
. Agora é necessário que o acima seja escrito como:
var x = $"""
Hello
{1 + 1}
World
""";
O tipo de delegado inferido para os métodos inclui os valores padrão dos parâmetros e o modificador params
Introduzido no Visual Studio 2022 versão 17.5
No .NET SDK versão 7.0.100 ou anterior, os tipos de delegados inferidos de métodos ignoravam os valores de parâmetros padrão e os modificadores params
, como demonstrado no código abaixo.
void Method(int i = 0, params int[] xs) { }
var action = Method; // System.Action<int, int[]>
DoAction(action, 1); // ok
void DoAction(System.Action<int, int[]> a, int p) => a(p, new[] { p });
No SDK do .NET 7.0.200 ou posterior, esses métodos são inferidos como tipos de delegados sintetizados anônimos com os mesmos valores padrão de parâmetro e os mesmos modificadores params
.
Essa alteração pode quebrar o código acima, conforme demonstrado abaixo:
void Method(int i = 0, params int[] xs) { }
var action = Method; // delegate void <anonymous delegate>(int arg1 = 0, params int[] arg2)
DoAction(action, 1); // error CS1503: Argument 1: cannot convert from '<anonymous delegate>' to 'System.Action<int, int[]>'
void DoAction(System.Action<int, int[]> a, int p) => a(p, new[] { p });
Você pode saber mais sobre essa alteração na proposta associada.
Para fins de análise de atribuição definitiva, invocações de funções locais assíncronas não são mais tratadas como sendo aguardadas
Introduzido no Visual Studio 2022 versão 17.5
Para fins de análise de atribuição definitiva, invocações de uma função local assíncrona não são mais tratadas como sendo aguardadas e, portanto, a função local não é considerada totalmente executada. Veja https://github.com/dotnet/roslyn/issues/43697 para a justificativa.
O código a seguir agora relatará um erro de atribuição definido:
public async Task M()
{
bool a;
await M1();
Console.WriteLine(a); // error CS0165: Use of unassigned local variable 'a'
async Task M1()
{
if ("" == String.Empty)
{
throw new Exception();
}
else
{
a = true;
}
}
}
Os nós INoneOperation
para atributos são agora nós IAttributeOperation
.
Introduzido no Visual Studio 2022 versão 17.5, SDK do .NET versão 7.0.200
Nas versões anteriores do compilador, a árvore IOperation
de um atributo estava enraizada com um nó INoneOperation
.
Adicionamos suporte nativo para atributos, o que significa que a raiz da árvore agora é um IAttributeOperation
. Alguns analisadores, incluindo versões mais antigas dos analisadores do SDK do .NET, não estão esperando essa forma de árvore e avisarão incorretamente (ou potencialmente não avisarão) ao encontrar essa forma. As soluções alternativas para isso são:
- Atualize a versão do analisador, se possível. Se estiver usando o SDK do .NET ou versões mais antigas do Microsoft.CodeAnalysis.FxCopAnalyzers, atualize para Microsoft.CodeAnalysis.NetAnalyzers 7.0.0-preview1.22464.1 ou mais recente.
- Suprime os falsos positivos dos analisadores até que eles possam ser atualizados com uma versão que leve essa alteração em conta.
Não há suporte para testes de tipo para ref
structs.
Introduzido no Visual Studio 2022 versão 17.4
Quando um tipo struct ref
é usado em um operador "is" ou "as", em alguns cenários, o compilador estava anteriormente relatando um aviso incorreto de que o teste de tipo sempre falharia em tempo de execução, omitindo a verificação real de tipo e levando a um comportamento incorreto. Quando o comportamento incorreto era possível durante a execução, o compilador produzirá um erro agora.
ref struct G<T>
{
public void Test()
{
if (this is G<int>) // Will now produce an error, used to be treated as always `false`.
{
Os resultados não utilizados de variável local de referência são desreferências.
Introduzido no Visual Studio 2022 versão 17.4
Quando uma variável local ref
é referenciada por valor, mas o resultado não é utilizado (como em uma atribuição para descartar), o resultado era ignorado anteriormente. O compilador agora desreferenciará esse local, garantindo que quaisquer efeitos colaterais sejam observados.
ref int local = Unsafe.NullRef<int>();
_ = local; // Will now produce a `NullReferenceException`
Tipos não podem ser nomeados scoped
Introduzido no Visual Studio 2022 versão 17.4. A partir do C# 11, os tipos não podem ser nomeados scoped
. O compilador relatará um erro em todos esses nomes de tipo. Para contornar isso, o nome do tipo e todos os usos devem ser escapados com um @
:
class scoped {} // Error CS9056
class @scoped {} // No error
ref scoped local; // Error
ref scoped.nested local; // Error
ref @scoped local2; // No error
Isso foi feito porque scoped
agora é um modificador para declarações de variáveis e reservado após ref
em um tipo ref.
Tipos não podem ser nomeados file
Introduzido no Visual Studio 2022 versão 17.4. A partir do C# 11, os tipos não podem ser nomeados file
. O compilador relatará um erro em todos esses nomes de tipo. Para contornar isso, o nome do tipo e todos os usos devem ser escapados com um @
:
class file {} // Error CS9056
class @file {} // No error
Foi feito porque file
agora é um modificador para declarações de tipo.
Você pode saber mais sobre essa alteração no problema de csharplang associado.
Espaços necessários em diretivas #line span
Introduzido no SDK do .NET 6.0.400, Visual Studio 2022 versão 17.3.
Quando a #line
diretiva span foi introduzida no C# 10, ela não exigiu nenhum espaçamento específico.
Por exemplo, isso seria válido: #line(1,2)-(3,4)5"file.cs"
.
No Visual Studio 17.3, o compilador requer espaços antes do primeiro parêntese, do offset de caractere e do nome do arquivo.
Portanto, o exemplo acima falha ao analisar, a menos que os espaços sejam adicionados: #line (1,2)-(3,4) 5 "file.cs"
.
Operadores verificados em System.IntPtr e System.UIntPtr
Introduzido no SDK do .NET 7.0.100, Visual Studio 2022 versão 17.3.
Quando a plataforma dá suporte a tipos numéricosIntPtr
e UIntPtr
(conforme indicado pela presença de System.Runtime.CompilerServices.RuntimeFeature.NumericIntPtr
), os operadores internos de nint
e nuint
se aplicam a esses tipos subjacentes.
Isso significa que, nessas plataformas, IntPtr
e UIntPtr
têm operadores internos checked
, que agora podem ser gerados quando ocorre um estouro.
IntPtr M(IntPtr x, int y)
{
checked
{
return x + y; // may now throw
}
}
unsafe IntPtr M2(void* ptr)
{
return checked((IntPtr)ptr); // may now throw
}
As possíveis soluções alternativas são:
- Especificar
unchecked
contexto - Faça downgrade para uma plataforma/TFM sem tipos
IntPtr
/UIntPtr
numéricos
Além disso, conversões implícitas entre IntPtr
/UIntPtr
e outros tipos numéricos são tratadas como conversões padrão nessas plataformas. Isso pode afetar a resolução de sobrecarga em alguns casos.
Essas alterações podem causar uma mudança de comportamento se o código do usuário dependesse de exceções de estouro em um contexto não verificado, ou se não estivesse esperando exceções de estouro em um contexto verificado. Um analisador foi adicionado na 7.0 para ajudar a detectar essas alterações comportamentais e tomar as medidas apropriadas. O analisador produzirá diagnósticos sobre possíveis alterações comportamentais, que são padrão para informações de severidade, mas podem ser atualizadas para avisos usando o editorconfig.
Adição de System.UIntPtr e System.Int32
Introduzido no SDK do .NET 7.0.100, Visual Studio 2022 versão 17.3.
Quando a plataforma dá suporte a tipos numéricosIntPtr
e UIntPtr
(conforme indicado pela presença de System.Runtime.CompilerServices.RuntimeFeature.NumericIntPtr
), o operador +(UIntPtr, int)
definido em System.UIntPtr
não pode mais ser usado.
Em vez disso, adicionar expressões de tipos System.UIntPtr
e um System.Int32
resulta em um erro.
UIntPtr M(UIntPtr x, int y)
{
return x + y; // error: Operator '+' is ambiguous on operands of type 'nuint' and 'int'
}
As possíveis soluções alternativas são:
- Use o
UIntPtr.Add(UIntPtr, int)
método:UIntPtr.Add(x, y)
- Aplique uma conversão não verificada para o tipo
nuint
no segundo operando:x + unchecked((nuint)y)
Operador Nameof em atributo no método ou na função local
Introduzido no SDK do .NET 6.0.400, Visual Studio 2022 versão 17.3.
Quando a versão da linguagem for C# 11 ou posterior, um operador nameof
em um atributo de um método colocará os parâmetros de tipo desse método em evidência. O mesmo se aplica a funções locais.
Um operador nameof
em um atributo de um método, seus parâmetros de tipo ou parâmetros, traz os parâmetros desse método para o escopo. O mesmo se aplica a funções locais, lambdas, delegados e indexadores.
Por exemplo, agora serão erros:
class C
{
class TParameter
{
internal const string Constant = """";
}
[MyAttribute(nameof(TParameter.Constant))]
void M<TParameter>() { }
}
class C
{
class parameter
{
internal const string Constant = """";
}
[MyAttribute(nameof(parameter.Constant))]
void M(int parameter) { }
}
As possíveis soluções alternativas são:
- Renomeie o parâmetro ou o parâmetro de tipo para evitar sombrear o nome do escopo externo.
- Use um literal de cadeia de caracteres em vez do operador
nameof
.
Não é possível retornar um parâmetro out como referência
Introduzido no SDK do .NET 7.0.100, Visual Studio 2022 versão 17.3.
Com a versão de linguagem C# 11 ou posterior ou com o .NET 7.0 ou posterior, um out
parâmetro não pode ser retornado por referência.
static ref T ReturnOutParamByRef<T>(out T t)
{
t = default;
return ref t; // error CS8166: Cannot return a parameter by reference 't' because it is not a ref parameter
}
As possíveis soluções alternativas são:
Use
System.Diagnostics.CodeAnalysis.UnscopedRefAttribute
para marcar a referência como não delimitada.static ref T ReturnOutParamByRef<T>([UnscopedRef] out T t) { t = default; return ref t; // ok }
Altere a assinatura do método para passar o parâmetro por
ref
.static ref T ReturnRefParamByRef<T>(ref T t) { t = default; return ref t; // ok }
O método de instância em struct ref pode capturar parâmetros ref não escopados
Introduzido no SDK do .NET 7.0.100, Visual Studio 2022 versão 17.4.
Com a versão de linguagem C# 11 ou posterior, ou com o .NET 7.0 ou posterior, supõe-se que uma invocação de método de instância capture parâmetros não escopados, como ref struct
ou ref
.
R<int> Use(R<int> r)
{
int i = 42;
r.MayCaptureArg(ref i); // error CS8350: may expose variables referenced by parameter 't' outside of their declaration scope
return r;
}
ref struct R<T>
{
public void MayCaptureArg(ref T t) { }
}
Uma possível solução alternativa, se o parâmetro ref
ou in
não for capturado no método de instância ref struct
, é declarar o parâmetro como scoped ref
ou scoped in
.
R<int> Use(R<int> r)
{
int i = 42;
r.CannotCaptureArg(ref i); // ok
return r;
}
ref struct R<T>
{
public void CannotCaptureArg(scoped ref T t) { }
}
A análise de escape do retorno de um struct ref do método depende do escape ref dos argumentos ref
Introduzido no SDK do .NET 7.0.100, Visual Studio 2022 versão 17.4.
Com a versão da linguagem C# 11 ou posterior ou com o .NET 7.0 ou posterior, um ref struct
retornado de uma invocação de método, seja como valor de retorno ou em parâmetros out
, só será safe-to-escape se todos os argumentos ref
e in
na invocação do método forem ref-safe-to-escape.
Os in
argumentos podem incluir valores de parâmetro padrão implícitos.
ref struct R { }
static R MayCaptureArg(ref int i) => new R();
static R MayCaptureDefaultArg(in int i = 0) => new R();
static R Create()
{
int i = 0;
// error CS8347: Cannot use a result of 'MayCaptureArg(ref int)' because it may expose
// variables referenced by parameter 'i' outside of their declaration scope
return MayCaptureArg(ref i);
}
static R CreateDefault()
{
// error CS8347: Cannot use a result of 'MayCaptureDefaultArg(in int)' because it may expose
// variables referenced by parameter 'i' outside of their declaration scope
return MayCaptureDefaultArg();
}
Uma possível solução alternativa, se o argumento ref
ou in
não for capturado no valor retornado ref struct
, é declarar o parâmetro como scoped ref
ou scoped in
.
static R CannotCaptureArg(scoped ref int i) => new R();
static R Create()
{
int i = 0;
return CannotCaptureArg(ref i); // ok
}
ref
para o argumento ref struct
considerado não delimitado em __arglist
Introduzido no SDK do .NET 7.0.100, Visual Studio 2022 versão 17.4.
Com a versão de linguagem C# 11 ou posterior ou com o .NET 7.0 ou posterior, uma conversão de ref
para um tipo ref struct
é considerada uma referência não delimitada quando passada como um argumento para __arglist
.
ref struct R { }
class Program
{
static void MayCaptureRef(__arglist) { }
static void Main()
{
var r = new R();
MayCaptureRef(__arglist(ref r)); // error: may expose variables outside of their declaration scope
}
}
Operador de deslocamento para a direita sem sinal
Introduzido no SDK do .NET 6.0.400, Visual Studio 2022 versão 17.3. A linguagem adicionou suporte para um operador "Deslocamento à Direita Sem Sinal" (>>>
).
Isso desabilita a capacidade de consumir métodos que implementam operadores "Deslocamento à Direita Sem Sinal" definidos pelo usuário como métodos regulares.
Por exemplo, há uma biblioteca existente desenvolvida em algum idioma (diferente de VB ou C#) que expõe um operador definido pelo usuário "Unsigned Right Shift" para o tipo C1
.
O código a seguir costumava compilar com êxito anteriormente.
static C1 Test1(C1 x, int y) => C1.op_UnsignedRightShift(x, y); //error CS0571: 'C1.operator >>>(C1, int)': cannot explicitly call operator or accessor
Uma possível solução alternativa é mudar para o uso do operador >>>
:
static C1 Test1(C1 x, int y) => x >>> y;
Enumerador Foreach como um struct ref
Introduzido no SDK do .NET 6.0.300, Visual Studio 2022 versão 17.2. Um foreach
usando um tipo de enumerador de struct ref relatará um erro se a versão da linguagem estiver definida como 7.3 ou anterior.
Isso corrige um bug onde o recurso tinha suporte em compiladores mais recentes destinados a uma versão do C# anterior ao suporte oficial.
As possíveis soluções alternativas são:
- Altere o
ref struct
tipo para umstruct
ouclass
tipo. - Atualize o
<LangVersion>
elemento para 7.3 ou posterior.
O foreach
assíncrono prefere o DisposeAsync
baseado no padrão a uma implementação explícita de interface de IAsyncDisposable.DisposeAsync()
Introduzido no SDK do .NET 6.0.300, Visual Studio 2022 versão 17.2. Um método assíncrono foreach
prefere vincular usando um padrão de método baseado em DisposeAsync()
em vez de IAsyncDisposable.DisposeAsync()
.
Por exemplo, o DisposeAsync()
será escolhido, em vez do IAsyncEnumerator<int>.DisposeAsync()
método em AsyncEnumerator
:
await foreach (var i in new AsyncEnumerable())
{
}
struct AsyncEnumerable
{
public AsyncEnumerator GetAsyncEnumerator() => new AsyncEnumerator();
}
struct AsyncEnumerator : IAsyncDisposable
{
public int Current => 0;
public async ValueTask<bool> MoveNextAsync()
{
await Task.Yield();
return false;
}
public async ValueTask DisposeAsync()
{
Console.WriteLine("PICKED");
await Task.Yield();
}
ValueTask IAsyncDisposable.DisposeAsync() => throw null; // no longer picked
}
Essa alteração corrige uma violação de especificação em que o método público DisposeAsync
está visível no tipo declarado, enquanto a implementação da interface explícita só é visível usando uma referência ao tipo de interface.
Para solucionar esse erro, remova o método DisposeAsync
baseado no padrão do seu tipo.
Não permitir cadeias de caracteres convertidas como um argumento padrão
Introduzido no SDK do .NET 6.0.300, Visual Studio 2022 versão 17.2. O compilador C# aceitaria valores de argumento padrão incorretos envolvendo uma conversão de referência de uma constante de cadeia de caracteres e emitiria null
como o valor constante em vez do valor padrão especificado na origem. No Visual Studio 17.2, isso se torna um erro. Consulte roslyn#59806.
Essa alteração corrige uma violação de especificação no compilador. Os argumentos padrão devem ser constantes de tempo de compilação. As versões anteriores permitiam o seguinte código:
void M(IEnumerable<char> s = "hello")
A declaração anterior exigia uma conversão de string
para IEnumerable<char>
. O compilador permitiu esse constructo e emitiria null
como o valor do argumento. O código anterior produz um erro do compilador a partir da versão 17.2.
Para contornar essa alteração, você pode fazer uma das seguintes alterações:
- Altere o tipo de parâmetro para que uma conversão não seja necessária.
- Altere o valor do argumento padrão para
null
restaurar o comportamento anterior.
A palavra-chave contextual var
como um tipo de retorno lambda explícito
Introduzido no SDK do .NET 6.0.200, Visual Studio 2022 versão 17.1. A palavra-chave contextual var não pode ser usada como um tipo de retorno lambda explícito.
Essa alteração permite possíveis recursos futuros, garantindo que var
continue a ser o tipo natural para o tipo de retorno de uma expressão lambda.
Você poderá encontrar esse erro se tiver um tipo nomeado var
e definir uma expressão lambda usando um tipo de retorno explícito ( var
o tipo).
using System;
F(var () => default); // error CS8975: The contextual keyword 'var' cannot be used as an explicit lambda return type
F(@var () => default); // ok
F(() => default); // ok: return type is inferred from the parameter to F()
static void F(Func<var> f) { }
public class var
{
}
As soluções alternativas incluem as seguintes alterações:
- Use
@var
como o tipo de retorno. - Remova o tipo de retorno explícito para que o compilador determine o tipo de retorno.
Manipuladores de cadeia de caracteres interpolados e inicialização do indexador
Introduzido no SDK do .NET 6.0.200, Visual Studio 2022 versão 17.1. Indexadores que utilizam um manipulador de cadeia de caracteres interpolado e exigem o receptor como uma entrada para o construtor não podem ser usados em um inicializador de objeto.
Essa alteração não permite um cenário de caso de borda em que inicializadores de indexadores usam um manipulador de cadeia de caracteres interpolado e esse manipulador de cadeia de caracteres interpolado usa o receptor do indexador como um parâmetro do construtor. O motivo dessa alteração é que esse cenário pode resultar no acesso a variáveis que ainda não foram inicializadas. Considere este exemplo:
using System.Runtime.CompilerServices;
// error: Interpolated string handler conversions that reference
// the instance being indexed cannot be used in indexer member initializers.
var c = new C { [$""] = 1 };
class C
{
public int this[[InterpolatedStringHandlerArgument("")] CustomHandler c]
{
get => ...;
set => ...;
}
}
[InterpolatedStringHandler]
class CustomHandler
{
// The constructor of the string handler takes a "C" instance:
public CustomHandler(int literalLength, int formattedCount, C c) {}
}
As soluções alternativas incluem as seguintes alterações:
- Remova o tipo de receptor do manipulador de cadeia de caracteres interpolada.
- Alterar o argumento para o indexador ser um
string
ref, readonly ref, in, out não são permitidos como parâmetros ou retornos em métodos somente para chamadas não gerenciadas
Introduzido no SDK do .NET 6.0.200, Visual Studio 2022 versão 17.1.ref
/ref readonly
/in
/out
não têm permissão para serem usados em retorno/parâmetros de um método atribuído com UnmanagedCallersOnly
.
Essa alteração é uma correção de bug. Valores e parâmetros de retorno não são blittable. Passar argumentos ou retornar valores por referência pode causar um comportamento indefinido. Nenhuma das seguintes declarações será compilada:
using System.Runtime.InteropServices;
[UnmanagedCallersOnly]
static ref int M1() => throw null; // error CS8977: Cannot use 'ref', 'in', or 'out' in a method attributed with 'UnmanagedCallersOnly'.
[UnmanagedCallersOnly]
static ref readonly int M2() => throw null; // error CS8977: Cannot use 'ref', 'in', or 'out' in a method attributed with 'UnmanagedCallersOnly'.
[UnmanagedCallersOnly]
static void M3(ref int o) => throw null; // error CS8977: Cannot use 'ref', 'in', or 'out' in a method attributed with 'UnmanagedCallersOnly'.
[UnmanagedCallersOnly]
static void M4(in int o) => throw null; // error CS8977: Cannot use 'ref', 'in', or 'out' in a method attributed with 'UnmanagedCallersOnly'.
[UnmanagedCallersOnly]
static void M5(out int o) => throw null; // error CS8977: Cannot use 'ref', 'in', or 'out' in a method attributed with 'UnmanagedCallersOnly'.
A solução alternativa é remover o modificador por referência.
Supõe-se que Length, Count sejam não negativos em padrões
Introduzido no SDK do .NET 6.0.200, Visual Studio 2022 versão 17.1. As propriedadesLength
e Count
em tipos contáveis e indexáveis são consideradas não negativas para fins de análise de subsunção e exaustividade de padrões e comutadores.
Esses tipos podem ser usados com o indexador de índice implícito e padrões de lista.
As propriedades Length
e Count
, embora classificadas como int
, são consideradas não negativas ao analisar padrões. Considere este método de exemplo:
string SampleSizeMessage<T>(IList<T> samples)
{
return samples switch
{
// This switch arm prevents a warning before 17.1, but will never happen in practice.
// Starting with 17.1, this switch arm produces a compiler error.
// Removing it won't introduce a warning.
{ Count: < 0 } => throw new InvalidOperationException(),
{ Count: 0 } => "Empty collection",
{ Count: < 5 } => "Too small",
{ Count: < 20 } => "reasonable for the first pass",
{ Count: < 100 } => "reasonable",
{ Count: >= 100 } => "fine",
};
}
void M(int[] i)
{
if (i is { Length: -1 }) {} // error: impossible under assumption of non-negative length
}
Antes da 17.1, o primeiro switch arm, era necessário testar se Count
era negativo para evitar um aviso de que nem todos os valores possíveis estavam cobertos. A partir do 17.1, o primeiro braço de switch gera um erro de compilador. A solução alternativa é remover os switch arms adicionados para os casos inválidos.
Essa alteração foi feita como parte da adição de padrões de lista. As regras de processamento serão mais consistentes se cada uso de uma Length
ou Count
propriedade em uma coleção for considerado não negativo. Você pode ler mais detalhes sobre a alteração no problema de design de linguagem.
A solução alternativa é remover os switch arms com condições inacessíveis.
Adicionar inicializadores de campo a um struct requer um construtor declarado explicitamente
Introduzido no SDK do .NET 6.0.200, Visual Studio 2022 versão 17.1.struct
declarações de tipo com inicializadores de campo devem incluir um construtor declarado explicitamente. Além disso, todos os campos devem ser atribuídos de forma definitiva em construtores de instância struct
que não têm um inicializador : this()
. Portanto, quaisquer campos que não foram atribuídos previamente devem ser atribuídos pelo construtor adicionado ou por inicializadores de campo. Consulte dotnet/csharplang#5552, dotnet/roslyn#58581.
Há duas maneiras de inicializar uma variável para seu valor padrão em C#: new()
e default
. Para classes, a diferença é evidente, pois new
cria uma nova instância e default
retorna null
. A diferença é mais sutil para structs, pois, no caso de default
, structs retornam uma instância em que cada campo/propriedade é definido com o seu valor padrão. Adicionamos inicializadores de campo para structs no C# 10. Inicializadores de campo são executados somente quando um construtor declarado explicitamente é executado. Significativamente, eles não são executados quando você usa default
ou cria uma matriz de qualquer struct
tipo.
Na versão 17.0, se houver inicializadores de campo, mas nenhum construtor declarado, um construtor sem parâmetros é sintetizado que executa inicializadores de campo. No entanto, isso significava que adicionar ou remover uma declaração de construtor pode afetar se um construtor sem parâmetros é sintetizado e, como resultado, pode alterar o comportamento de new()
.
Para resolver o problema, no SDK do .NET 6.0.200 (VS 17.1), o compilador não sintetiza mais um construtor sem parâmetros. Se um struct
contém inicializadores de campo e nenhum construtor explícito, o compilador gera um erro. Se um struct
tem inicializadores de campo, ele deve declarar um construtor, pois caso contrário, os inicializadores de campo nunca são executados.
Além disso, todos os campos que não têm inicializadores de campo devem ser atribuídos em cada struct
construtor, a menos que o construtor tenha um : this()
inicializador.
Por exemplo:
struct S // error CS8983: A 'struct' with field initializers must include an explicitly declared constructor.
{
int X = 1;
int Y;
}
A solução alternativa é declarar um construtor. A menos que os campos não tenham sido atribuídos anteriormente, esse construtor pode, e muitas vezes, ser um construtor sem parâmetros vazio:
struct S
{
int X = 1;
int Y;
public S() { Y = 0; } // ok
}
Os especificadores de formato não podem conter chaves
Introduzido no SDK do .NET 6.0.200, na versão 17.1 do Visual Studio 2022. Os especificadores de formato em cadeias de caracteres interpoladas não podem conter chaves (sejam {
ou }
). Nas versões anteriores, {{
foi interpretado como um escape {
, e }}
foi interpretado como um caractere escapado }
no especificador de formato. Agora, o primeiro }
char em um especificador de formato termina a interpolação e qualquer {
char é um erro.
Isso torna o processamento de strings interpoladas consistente com o processamento para System.String.Format
:
using System;
Console.WriteLine($"{{{12:X}}}");
//prints now: "{C}" - not "{X}}"
X
é o formato para hexadecimal maiúsculo e C
é o valor hexadecimal para 12.
A solução alternativa é remover as chaves extras da cadeia de caracteres de formato.
Você pode saber mais sobre essa alteração no problema de roslyn associado.
Tipos não podem ser nomeados required
Introduzido no Visual Studio 2022 versão 17.3. A partir do C# 11, os tipos não podem ser nomeados required
. O compilador relatará um erro em todos esses nomes de tipo. Para contornar isso, o nome do tipo e todos os usos devem ser escapados com um @
:
class required {} // Error CS9029
class @required {} // No error
Isso foi feito pois required
agora é um modificador de membro para propriedades e campos.
Você pode saber mais sobre essa alteração no problema de csharplang associado.
Roslyn breaking changes