Alterações significativas no Roslyn após o .NET 8.0.100 até o .NET 9.0.100
Este documento lista as alterações recentes conhecidas no Roslyn após o lançamento geral do .NET 8 (.NET SDK versão 8.0.100) até o lançamento geral do .NET 9 (.NET SDK versão 9.0.100).
O atributo InlineArray em um tipo struct de registro não é mais permitido.
Introduzido no Visual Studio 2022 versão 17.11
[System.Runtime.CompilerServices.InlineArray(10)] // error CS9259: Attribute 'System.Runtime.CompilerServices.InlineArray' cannot be applied to a record struct.
record struct Buffer1()
{
private int _element0;
}
[System.Runtime.CompilerServices.InlineArray(10)] // error CS9259: Attribute 'System.Runtime.CompilerServices.InlineArray' cannot be applied to a record struct.
record struct Buffer2(int p1)
{
}
Os iteradores introduzem contexto seguro em C# 13 e versões mais recentes
Introduzido no Visual Studio 2022 versão 17.11
Embora a especificação da linguagem afirme que os iteradores introduzem um contexto seguro, Roslyn não implementa isso em C# 12 e inferior. Isso mudará no C# 13 como parte do um recurso que permite código não seguro em iteradores. A alteração não quebra cenários normais, pois não era permitido usar construções inseguras diretamente em iteradores de qualquer maneira. No entanto, ele pode quebrar cenários em que um contexto inseguro foi anteriormente herdado em funções locais aninhadas, por exemplo:
unsafe class C // unsafe context
{
System.Collections.Generic.IEnumerable<int> M() // an iterator
{
yield return 1;
local();
void local()
{
int* p = null; // allowed in C# 12; error in C# 13
}
}
}
Você pode contornar a quebra simplesmente adicionando o modificador unsafe
à função local.
Expressão de coleção quebrando alterações com resolução de sobrecarga em C# 13 e mais recentes
Introduzido no Visual Studio 2022, a partir da Versão 17.12 e posteriores, quando se utiliza C# 13+
Há algumas alterações na vinculação de expressão de coleção em C# 13. A maioria destes está transformando ambiguidades em compilações bem-sucedidas, mas algumas representam alterações disruptivas que resultam num novo erro de compilação ou uma alteração que provoca uma mudança de comportamento. Eles são detalhados abaixo.
Expressões de coleção vazias já não utilizam se uma API é um span para resolver ambiguidades em sobrecargas.
Quando uma expressão de coleção vazia é fornecida a um método sobrecarregado e não há um tipo de elemento claro, não usamos mais se uma API leva um ReadOnlySpan<T>
ou um Span<T>
para decidir se prefere essa API. Por exemplo:
class C
{
static void M(ReadOnlySpan<int> ros) {}
static void M(Span<object> s) {}
static void Main()
{
M([]); // C.M(ReadOnlySpan<int>) in C# 12, error in C# 13.
}
}
O tipo exato de elemento é preferido sobre tudo o resto
No C# 13, priorizamos uma correspondência exata de tipo de elemento, analisando conversões de expressões. Isso pode resultar em uma mudança de comportamento ao envolver constantes:
class C
{
static void M1(ReadOnlySpan<byte> ros) {}
static void M1(Span<int> s) {}
static void M2(ReadOnlySpan<string> ros) {}
static void M2(Span<CustomInterpolatedStringHandler> ros) {}
static void Main()
{
M1([1]); // C.M(ReadOnlySpan<byte>) in C# 12, C.M(Span<int>) in C# 13
M2([$"{1}"]); // C.M(ReadOnlySpan<string>) in C# 12, C.M(Span<CustomInterpolatedStringHandler>) in C# 13
}
}
A declaração de indexadores na ausência de declaração adequada de DefaultMemberAttribute não é mais permitida.
Introduzido no Visual Studio 2022 versão 17.13
public interface I1
{
public I1 this[I1 args] { get; } // error CS0656: Missing compiler required member 'System.Reflection.DefaultMemberAttribute..ctor'
}
Os parâmetros padrão e params são considerados no tipo natural do grupo de métodos
Introduzido no Visual Studio 2022 versão 17.13
Anteriormente, o compilador inesperadamente inferido diferentes tipos de delegados, dependendo da ordem dos candidatos na fonte quando os valores de parâmetros padrão ou matrizes params
foram usados. Agora é emitido um erro de ambiguidade.
using System;
class Program
{
static void Main()
{
var x1 = new Program().Test1; // previously Action<long[]> - now error
var x2 = new Program().Test2; // previously anonymous void delegate(params long[]) - now error
x1();
x2();
}
}
static class E
{
static public void Test1(this Program p, long[] a) => Console.Write(a.Length);
static public void Test1(this object p, params long[] a) => Console.Write(a.Length);
static public void Test2(this object p, params long[] a) => Console.Write(a.Length);
static public void Test2(this Program p, long[] a) => Console.Write(a.Length);
}
Em LangVersion=12
ou inferior, o modificador params
deve ser consistente em todos os métodos para inferir uma assinatura única de delegado.
Observe que isto não afeta o LangVersion=13
e os posteriores por causa de um algoritmo diferente de inferência de delegados.
var d = new C().M; // previously inferred Action<int[]> - now error CS8917: the delegate type could not be inferred
static class E
{
public static void M(this C c, params int[] x) { }
}
class C
{
public void M(int[] x) { }
}
Uma solução alternativa é usar tipos de delegados explícitos em vez de confiar na inferência de var
nesses casos.
dotnet_style_require_accessibility_modifiers
agora se aplica consistentemente aos membros da interface
PR: https://github.com/dotnet/roslyn/pull/76324
Antes dessa alteração, o analisador de código para dotnet_style_require_accessibility_modifiers simplesmente ignorava os membros da interface. Isso ocorreu porque o C# inicialmente não permitia modificadores para membros da interface inteiramente, fazendo com que eles sempre fossem públicos.
Versões posteriores do idioma relaxaram essa restrição, permitindo que os usuários forneçam modificadores de acessibilidade nos membros da interface, incluindo um modificador de public
redundante.
O analisador foi atualizado para agora também aplicar o valor desta opção nos membros da interface. O significado do valor é o seguinte:
-
never
. O analisador não faz análise. Modificadores redundantes são permitidos em todos os membros. -
always
. Modificadores redundantes são sempre necessários em todos os membros (incluindo membros da interface). Por exemplo: um modificador deprivate
em um membro de classe e um modificador depublic
em um membro da interface. Se considerar que todos os membros, independentemente de qualquer circunstância, devem declarar explicitamente a sua acessibilidade, esta é a opção a utilizar. -
for_non_interface_members
. Modificadores redundantes são necessários em todos os membros que não são parte de uma interface, mas não são permitidos para membros da interface. Por exemplo:private
será exigido aos membros da classe privada. No entanto, um membro da interface pública não poderá ter modificadores depublic
redundantes. Isso corresponde à abordagem de modificador padrão existente antes de a linguagem permitir modificadores em membros da interface. -
omit_if_default
. Modificadores redundantes não são permitidos. Por exemplo, um membro de classe privada será proibido de usarprivate
e um membro da interface pública será proibido de usarpublic
. Esta é a opção a ser usada se você achar que reafirmar a acessibilidade quando ela corresponde ao que o idioma escolhe por padrão é redundante e não deve ser permitido.
Roslyn breaking changes