Compartir a través de


Cambios importantes en Roslyn después de .NET 7.0.100 a .NET 8.0.100

En este documento se enumeran los cambios importantes conocidos en Roslyn después de la versión general de .NET 7 (versión 7.0.100 del SDK de .NET) hasta la versión general de .NET 8 (versión 8.0.100 del SDK de .NET).

Los modificadores ref de argumentos dinámicos deben ser compatibles con modificadores ref de los parámetros correspondientes.

Introducido en Visual Studio 2022, versión 17.10

Los modificadores ref de argumentos dinámicos deben ser compatibles con los modificadores ref de los parámetros correspondientes durante la compilación. Esto puede provocar un fallo en la resolución de una sobrecarga que implique argumentos dinámicos en tiempo de compilación en lugar de en tiempo de ejecución.

Anteriormente, se permitía un desajuste en tiempo de compilación, lo que retrasaba el fallo de resolución de sobrecarga hasta el tiempo de ejecución.

Por ejemplo, el siguiente código solía compilarse sin errores, pero producía un error con la excepción: "Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: El mejor método sobrecargado para 'C.f(ref object)' tiene algunos argumentos no válidos". Ahora produce un error de compilación.

public class C
{
    public void f(ref dynamic a) 
    {
    }
    
    public void M(dynamic d)
    {
        f(d); // error CS1620: Argument 1 must be passed with the 'ref' keyword
    }
}

La expresión de colección para la implementación de tipos IEnumerable debe tener elementos convertibles implícitamente a object

Introducido en Visual Studio 2022, versión 17.10

La conversión de una expresión de colección a un struct o class que implementa System.Collections.IEnumerable y no tiene un GetEnumerator() fuertemente tipado requiere que los elementos de la expresión de colección se conviertan implícitamente a object. Anteriormente, se supone que los elementos de una expresión de colección que tienen como destino una IEnumerable implementación se pueden convertir a objecty se convierten solo cuando se enlazan al método aplicable Add .

Este requisito adicional significa que la conversión de expresiones de colección a implementaciones IEnumerable se trata de forma coherente con otros tipos de destino en los que los elementos de la expresión de colección se deben convertir implícitamente en el tipo de iteración del tipo de destino.

Este cambio afecta a las expresiones de colección dirigidas a implementaciones IEnumerable donde los elementos dependen de la tipificación por destino para un tipo de parámetro de método Add fuertemente tipado. En el ejemplo siguiente, se notifica un error que _ => { } no se puede convertir implícitamente en object.

class Actions : IEnumerable
{
    public void Add(Action<int> action);
    // ...
}

Actions a = [_ => { }]; // error CS8917: The delegate type could not be inferred.

Para resolver el error, la expresión de elemento podría escribirse explícitamente.

a = [(int _) => { }];          // ok
a = [(Action<int>)(_ => { })]; // ok

El tipo de destino de la expresión de colección debe tener un constructor y un método Add

Introducido en Visual Studio 2022, versión 17.10

La conversión de una expresión de colección a un struct o class que implementa System.Collections.IEnumerable y no tiene un CollectionBuilderAttribute requiere que el tipo de destino tenga un constructor accesible al que se pueda llamar sin argumentos y, si la expresión de colección no está vacía, el tipo de destino debe tener un método accesible Add que se pueda llamar con un único argumento.

Anteriormente, el constructor y los métodos Add eran necesarios para la construcción de la instancia de colección, pero no para la conversión. Esto significaba que la siguiente llamada era ambigua, ya que tanto char[] como string eran tipos de destino válidos para la expresión de colección. La llamada ya no es ambigua porque string no tiene un constructor o Add método sin parámetros.

Print(['a', 'b', 'c']); // calls Print(char[])

static void Print(char[] arg) { }
static void Print(string arg) { }

Los argumentos ref se pueden pasar a parámetros in

Introducido en Visual Studio 2022, versión 17.8p2

Los parámetros de la característica ref readonly relajan la resolución de sobrecarga, lo que permite pasar argumentos ref a parámetros in cuando LangVersion se establece en 12 o posterior. Esto puede provocar cambios importantes en el comportamiento o la fuente.

var i = 5;
System.Console.Write(new C().M(ref i)); // prints "E" in C# 11, but "C" in C# 12
System.Console.Write(E.M(new C(), ref i)); // workaround: prints "E" always

class C
{
    public string M(in int i) => "C";
}
static class E
{
    public static string M(this C c, ref int i) => "E";
}
var i = 5;
System.Console.Write(C.M(null, ref i)); // prints "1" in C# 11, but fails with an ambiguity error in C# 12
System.Console.Write(C.M((I1)null, ref i)); // workaround: prints "1" always

interface I1 { }
interface I2 { }
static class C
{
    public static string M(I1 o, ref int x) => "1";
    public static string M(I2 o, in int x) => "2";
}

Preferir el desecho basado en patrones en lugar de basado en interfaces en using asincrónico

Introducido en Visual Studio 2022, versión 17.10p3

Un using asincrónico prefiere enlazar usando un método DisposeAsync() basado en un patrón en lugar de IAsyncDisposable.DisposeAsync() basado en interfaz.

Por ejemplo, se seleccionará el método público DisposeAsync() , en lugar de la implementación de la interfaz privada:

await using (var x = new C()) { }

public class C : System.IAsyncDisposable
{
    ValueTask IAsyncDisposable.DisposeAsync() => throw null; // no longer picked

    public async ValueTask DisposeAsync()
    {
        Console.WriteLine("PICKED");
        await Task.Yield();
    }
}