Dela via


Kritiska ändringar i Roslyn mellan .NET 7.0.100 och .NET 8.0.100

Det här dokumentet listar kända brytningsändringar i Roslyn efter den allmänna utgåvan av .NET 7 (.NET SDK version 7.0.100) till och med den allmänna utgåvan av .NET 8 (.NET SDK version 8.0.100).

Referensmodifierare för dynamiska argument bör vara kompatibla med refmodifierare för motsvarande parametrar

Introducerades i Visual Studio 2022 version 17.10

Referensmodifierare för dynamiska argument bör vara kompatibla med refmodifierare för motsvarande parametrar vid kompileringstillfället. Detta kan orsaka att en överbelastningsupplösning som innebär att dynamiska argument misslyckas vid kompileringstidpunkt i stället för vid körningstidpunkt.

Tidigare tilläts ett matchningsfel vid kompileringstillfället, vilket fördröjde överbelastningsmatchningsfelet till körningen.

Följande kod används till exempel för att kompilera utan fel, men misslyckades med undantagsfel: "Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: Den bästa överlagrade metodmatchningen för 'C.f(ref object)' har några ogiltiga argument" Det kommer att generera ett kompileringsfel nu.

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
    }
}

Samlingsuttryck för typ som implementerar IEnumerable måste ha element som är implicit konverterbara till object

Introducerades i Visual Studio 2022 version 17.10

Konvertering av ett samlingsuttryck till en struct eller class som implementerar System.Collections.IEnumerable och inte har ett starkt skrivet GetEnumerator() kräver att elementen i samlingsuttrycket implicit konverteras till object. Tidigare antogs elementen i ett samlingsuttryck som riktar sig mot en IEnumerable implementering vara konvertibla till objectoch konverterades endast vid bindning till den tillämpliga Add metoden.

Det här ytterligare kravet innebär att konverteringar av samlingsuttryck till IEnumerable implementeringar behandlas konsekvent med andra måltyper där elementen i samlingsuttrycket implicit måste konverteras till iterationstypen för måltypen.

Den här ändringen påverkar samlingsuttryck som riktar sig mot IEnumerable-implementationer där elementen förlitar sig på typanpassning till en starkt typad metodparametertyp Add. I exemplet nedan rapporteras ett fel som _ => { } inte kan konverteras implicit till object.

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

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

För att lösa felet kan elementuttrycket uttryckligen skrivas.

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

Måltyp för samlingsuttryck måste ha konstruktor och Add metod

Introducerades i Visual Studio 2022 version 17.10

Konvertering av ett samlingsuttryck till en struct eller class som implementerar System.Collections.IEnumerable och inte har en CollectionBuilderAttribute kräver att måltypen har en tillgänglig konstruktor som kan anropas utan argument och om samlingsuttrycket inte är tomt måste måltypen ha en tillgänglig Add metod som kan anropas med ett enda argument.

Tidigare krävdes konstruktorn och metoderna för konstruktion av samlingsinstansen, men inte för konvertering. Det innebar att följande anrop var tvetydigt eftersom båda char[] och string var giltiga måltyper för samlingsuttrycket. Anropet är inte längre tvetydigt eftersom string det inte finns någon parameterlös konstruktor eller Add metod.

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

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

ref argument kan skickas till in parametrar

Introducerades i Visual Studio 2022 version 17.8p2

Funktionenref readonly släppte överbelastningsmatchningen vilket möjliggör att ref argument kan skickas till in parametrar när LangVersion inställd till 12 eller senare. Detta kan leda till beteende eller ändringar som bryter källkod:

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";
}

Föredrar mönsterbaserad framför gränssnittsbaserad borttagning i asynkronisering using

Introducerades i Visual Studio 2022 version 17.10p3

En asynkron using metod föredrar att binda med hjälp av en mönsterbaserad DisposeAsync() metod i stället för gränssnittsbaserad IAsyncDisposable.DisposeAsync().

Den offentliga DisposeAsync() metoden väljs till exempel i stället för implementeringen av det privata gränssnittet:

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();
    }
}