Compartilhar via


Alterações interruptivas no Roslyn após o .NET 6.0.100 até o .NET 7.0.100

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:

  1. Especificar unchecked contexto
  2. 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:

  1. Use o UIntPtr.Add(UIntPtr, int) método: UIntPtr.Add(x, y)
  2. 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:

  1. Renomeie o parâmetro ou o parâmetro de tipo para evitar sombrear o nome do escopo externo.
  2. 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:

  1. 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
    }
    
  2. 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:

  1. Altere o ref struct tipo para um struct ou class tipo.
  2. 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:

  1. Altere o tipo de parâmetro para que uma conversão não seja necessária.
  2. 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:

  1. Use @var como o tipo de retorno.
  2. 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:

  1. Remova o tipo de receptor do manipulador de cadeia de caracteres interpolada.
  2. 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.