Dela via


Brytande ändringar i Roslyn från .NET 6.0.100 till .NET 7.0.100

Det här dokumentet listar kända icke-bakåtkompatibla ändringar i Roslyn från den allmänna versionen av .NET 6 (.NET SDK version 6.0.100) till den allmänna versionen av .NET 7 (.NET SDK version 7.0.100).

Alla lokala variabler av begränsade typer är inte tillåtna i asynkrona metoder

Introducerades i Visual Studio 2022 version 17.6p1

Asynkrona metoder tillåter inte lokala variabler av restriktiva typer. Men i tidigare versioner misslyckades kompilatorn med att upptäcka vissa implicit deklarerade lokala variabler. Till exempel i foreach- eller using-satser eller dekonstruktioner.
Nu är sådana implicit deklarerade lokala variabler inte längre tillåtna.

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

Se https://github.com/dotnet/roslyn/pull/66264

Pekare måste alltid vara i osäkra kontexter.

Introducerades i Visual Studio 2022 version 17.6

I tidigare SDK:er tillät kompilatorn ibland platser där pekare kunde refereras, utan att uttryckligen markera platsen som osäker. Modifieraren unsafe måste finnas.
Till exempel using Alias = List<int*[]>; bör ändras till using unsafe Alias = List<int*[]>; för att vara lagligt.
En användning som void Method(Alias a) ... bör ändras till unsafe void Method(Alias a) ....

Regeln är ovillkorlig, förutom using aliasdeklarationer (som inte tillät en unsafe modifierare före C# 12).
Så för using deklarationer börjar regeln endast gälla om språkversionen väljs som C# 12 eller senare.

System.TypedReference betraktas som hanterat

Introducerades i Visual Studio 2022 version 17.6

Framöver betraktas System.TypedReference typ som hanterad.

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
}

Ref säkerhetsfel påverkar inte konvertering från lambda-uttryck till delegattyp

Introducerades i Visual Studio 2022 version 17.5

Referenssäkerhetsfel som rapporteras i en lambda-kropp påverkar inte längre lambda-uttryckets möjlighet att konverteras till en delegattyp. Den här ändringen kan påverka överbelastningsupplösningen.

I exemplet nedan är anropet till M(x => ...) tvetydigt med Visual Studio 17.5 eftersom både M(D1) och M(D2) nu anses vara tillämpliga, även om anropet till F(ref x, ref y) i lambda-brödtexten resulterar i en referenssäkerhet med M(D1) (se exemplen i d1 och d2 för jämförelse). Tidigare var anropet entydigt bundet till M(D2) eftersom överlagringen M(D1) inte ansågs vara tillämplig.

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

Om du vill lösa överbelastningsmatchningsändringarna använder du explicita typer för lambda-parametrarna eller ombudet.

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

Råa stränginterpolationer i början av raden.

Introducerades i Visual Studio 2022 version 17.5

I .NET SDK 7.0.100 eller tidigare tilläts följande felaktigt:

var x = $"""
    Hello
{1 + 1}
    World
    """;

Detta bröt mot regeln att radinnehållet (inklusive var en interpolering börjar) måste börja med samma mängd blanksteg som den slutliga """; raden. Det krävs nu att ovanstående skrivs som:

var x = $"""
    Hello
    {1 + 1}
    World
    """;

Härledd delegerad typ för metoder innehåller standardparametervärden och params-modifierare

Introducerades i Visual Studio 2022 version 17.5

I .NET SDK 7.0.100 eller tidigare ignorerade de delegeringstyper som härleddes från metoder standardparametervärden och params modifierare, som visas i följande kod:

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

I .NET SDK 7.0.200 eller senare, härleds sådana metoder som anonyma syntetiserade delegerade typer med samma standardvärden för parametrar och params modifierare. Den här ändringen kan bryta koden ovan enligt nedan:

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

Du kan lära dig mer om den här ändringen i det associerade förslaget.

Vid en bestämd tilldelningsanalys behandlas inte längre anrop av asynkrona lokala funktioner som väntande

Introducerades i Visual Studio 2022 version 17.5

För en bestämd tilldelningsanalys behandlas inte längre anrop av en asynkron lokal funktion som väntande och därför anses den lokala funktionen inte vara helt körd. Se https://github.com/dotnet/roslyn/issues/43697 för motiveringen.

Koden nedan kommer nu att rapportera ett definitivt tilldelningsfel:

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

INoneOperation noder för attribut är nu IAttributeOperation-noder.

Introducerades i Visual Studio 2022 version 17.5, .NET SDK version 7.0.200

I tidigare versioner av kompilatorn IOperation rotades trädet för ett attribut med en INoneOperation nod. Vi har lagt till inbyggt stöd för attribut, vilket innebär att roten i trädet nu är en IAttributeOperation. Vissa analysverktyg, inklusive äldre versioner av .NET SDK-analysverktygen, förväntar sig inte den här trädformen och varnar felaktigt (eller kan inte varna) när de stöter på den. Lösningarna för detta är:

  • Uppdatera din analysversion om möjligt. Om du använder .NET SDK eller äldre versioner av Microsoft.CodeAnalysis.FxCopAnalyzers uppdaterar du till Microsoft.CodeAnalysis.NetAnalyzers 7.0.0-preview1.22464.1 eller senare.
  • Utelämna falska positiva identifieringar från analysverktygen tills de kan uppdateras med en version som tar hänsyn till den här ändringen.

Typtester för ref structs stöds inte.

Introducerades i Visual Studio 2022 version 17.4

När en ref struct-typ används i en "is" eller "as"-operator, rapporterade kompilatorn tidigare i vissa scenarier en felaktig varning om att typkontrollen alltid misslyckades, och utelämnade den faktiska typen, vilket resulterade i felaktigt beteende. När ett felaktigt beteende vid körningstillfället var möjligt skapar kompilatorn nu ett fel i stället.

ref struct G<T>
{
    public void Test()
    {
        if (this is G<int>) // Will now produce an error, used to be treated as always `false`.
        {

Oanvända resultat från lokala referenser är avrefereringar.

Introducerades i Visual Studio 2022 version 17.4

När en ref lokal variabel refereras som värde, men resultatet inte används (till exempel genom att tilldela det till en discard), ignorerades resultatet tidigare. Kompilatorn kommer nu att avreferera den lokala variabeln, vilket säkerställer att eventuella bieffekter observeras.

ref int local = Unsafe.NullRef<int>();
_ = local; // Will now produce a `NullReferenceException`

Typer kan inte namnges scoped

Introducerades i Visual Studio 2022 version 17.4. Från och med C# 11 kan typer inte namnges scoped. Kompilatorn rapporterar ett fel om alla sådana typnamn. Om du vill kringgå detta måste typnamnet och alla användningar vara undantagna med en @:

class scoped {} // Error CS9056
class @scoped {} // No error
ref scoped local; // Error
ref scoped.nested local; // Error
ref @scoped local2; // No error

Detta gjordes då scoped nu är en modifierare för variabeldeklarationer och reserverad efter ref i en referenstyp.

Typer kan inte namnges file

Introducerades i Visual Studio 2022 version 17.4. Från och med C# 11 kan typer inte namnges file. Kompilatorn rapporterar ett fel om alla sådana typnamn. Om du vill kringgå detta måste typnamnet och alla användningar vara undantagna med en @:

class file {} // Error CS9056
class @file {} // No error

Detta gjordes eftersom file nu är en modifierare för typdeklarationernas.

Du kan läsa mer om den här ändringen i det associerade csharplang-problemet.

Nödvändiga blanksteg i #line span-direktiv

Introducerades i .NET SDK 6.0.400, Visual Studio 2022 version 17.3.

#line När span-direktivet infördes i C# 10 krävde det inget särskilt avstånd.
Detta skulle till exempel vara giltigt: #line(1,2)-(3,4)5"file.cs".

I Visual Studio 17.3 kräver kompilatorn blanksteg före den första parentesen, teckenförskjutningen och filnamnet.
Exemplet ovan kan därför inte parsas om inte blanksteg läggs till: #line (1,2)-(3,4) 5 "file.cs".

Kontrollerade operatörer för System.IntPtr och System.UIntPtr

Introducerades i .NET SDK 7.0.100, Visual Studio 2022 version 17.3.

När plattformen stöder numeriskaIntPtr och UIntPtr typer (vilket indikeras av förekomsten av System.Runtime.CompilerServices.RuntimeFeature.NumericIntPtr) kommer de inbyggda operatorerna från nint och nuint gäller för dessa underliggande typer. Det innebär att på sådana plattformar IntPtr och UIntPtr har inbyggda checked operatorer, som nu kan kasta när ett spill uppstår.

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
}

Möjliga lösningar är:

  1. Ange unchecked kontext
  2. Nedgradera till en plattform/TFM utan numeriska IntPtr/UIntPtr typer

Dessutom behandlas implicita konverteringar mellan IntPtr/UIntPtr och andra numeriska typer som standardkonverteringar på sådana plattformar. Detta kan påverka överbelastningslösningen i vissa fall.

Dessa ändringar kan orsaka en beteendeförändring om användarkoden var beroende av undantag för spill i en omarkerad kontext, eller om den inte förväntade sig undantag för spill i en kontrollerad kontext. En analysator lades till i 7.0 för att identifiera sådana beteendeändringar och vidta lämpliga åtgärder. Analysatorn skapar diagnostik för potentiella beteendeändringar, som standard är allvarlighetsgraden för information men kan uppgraderas till varningar via editorconfig.

Tillägg av System.UIntPtr och System.Int32

Introducerades i .NET SDK 7.0.100, Visual Studio 2022 version 17.3.

När plattformen stöder numeriskaIntPtr och UIntPtr typer (vilket indikeras av förekomsten av System.Runtime.CompilerServices.RuntimeFeature.NumericIntPtr), kan operatorn +(UIntPtr, int) som definieras i System.UIntPtr inte längre användas. I stället resulterar det i ett fel att lägga till uttryck av typerna System.UIntPtr och System.Int32.

UIntPtr M(UIntPtr x, int y)
{
    return x + y; // error: Operator '+' is ambiguous on operands of type 'nuint' and 'int'
}

Möjliga lösningar är:

  1. UIntPtr.Add(UIntPtr, int) Använd metoden:UIntPtr.Add(x, y)
  2. Använd en omarkerad gjutning för att skriva nuint på den andra operanden: x + unchecked((nuint)y)

Namn på operator i attribut för metod eller lokal funktion

Introducerades i .NET SDK 6.0.400, Visual Studio 2022 version 17.3.

När språkversionen är C# 11 eller senare gör en nameof-operator i ett attribut på en metod typparametrarna för metoden tillgängliga. Samma sak gäller för lokala funktioner.
En nameof-operator i ett attribut för en metod, dess typparametrar eller parametrar synliggör parametrarna för den metoden. Samma sak gäller för lokala funktioner, lambdas, ombud och indexerare.

Det här är till exempel nu fel:

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

Möjliga lösningar är:

  1. Byt namn på typparametern eller parametern för att undvika att skugga namnet från det yttre omfånget.
  2. Använd en strängliteral i stället för operatorn nameof .

Det går inte att returnera en out-parameter som referens

Introducerades i .NET SDK 7.0.100, Visual Studio 2022 version 17.3.

Med språkversion C# 11 eller senare, eller med .NET 7.0 eller senare, kan inte en out parameter returneras med referens.

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
}

Möjliga lösningar är:

  1. Använd System.Diagnostics.CodeAnalysis.UnscopedRefAttribute för att markera referensen som oomspänd.

    static ref T ReturnOutParamByRef<T>([UnscopedRef] out T t)
    {
        t = default;
        return ref t; // ok
    }
    
  2. Ändra metodsignaturen så att parametern skickas av ref.

    static ref T ReturnRefParamByRef<T>(ref T t)
    {
        t = default;
        return ref t; // ok
    }
    

Instansmetod på ref-struktur kan samla in referensparametrar utan scope

Introducerades i .NET SDK 7.0.100, Visual Studio 2022 version 17.4.

Med språkversion C# 11 eller senare, eller med .NET 7.0 eller senare, antas en instansmetodanrop av ref struct för att samla in parametrar som inte är scoped ref eller in parametrar.

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

En möjlig lösning, om parametern ref eller in inte samlas in i ref struct instansmetoden, är att deklarera parametern som scoped ref eller 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) { }
}

Metoden ref struct return escape analysis beror på ref escape av ref argument

Introducerades i .NET SDK 7.0.100, Visual Studio 2022 version 17.4.

Med språkversion C# 11 eller senare, eller med .NET 7.0 eller senare, är en ref struct som returneras från ett metodanrop, antingen som ett returvärde eller i out parametrar, endast säker för undantag om alla ref och in argument till metodanropet är referens-säkra för undantag. Argumenten in kan innehålla implicita standardparametervärden.

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

En möjlig lösning, om ref argumentet eller in inte samlas in i ref struct returvärdet, är att deklarera parametern som scoped ref eller scoped in.

static R CannotCaptureArg(scoped ref int i) => new R();

static R Create()
{
    int i = 0;
    return CannotCaptureArg(ref i); // ok
}

ref till ref struct argument anses vara ospecificerad i __arglist

Introducerades i .NET SDK 7.0.100, Visual Studio 2022 version 17.4.

Med språkversion C# 11 eller senare, eller med .NET 7.0 eller senare, betraktas en ref till en ref struct typ som en icke-scoped referens när den skickas som ett argument till __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
    }
}

Osignerad höger skiftoperator

Introducerades i .NET SDK 6.0.400, Visual Studio 2022 version 17.3. Språket har lagt till stöd för operatorn "Unsigned Right Shift" (>>>). Detta inaktiverar möjligheten att använda metoder som implementerar användardefinierade operatorer för "Osignerat högerskift" som vanliga metoder.

Det finns till exempel ett befintligt bibliotek som har utvecklats på något språk (förutom VB eller C#) och som visar en användardefinierad operator "Osignerat högerskift" för typen C1. Följande kod brukade kompilera framgångsrikt tidigare:

static C1 Test1(C1 x, int y) => C1.op_UnsignedRightShift(x, y); //error CS0571: 'C1.operator >>>(C1, int)': cannot explicitly call operator or accessor

En möjlig lösning är att växla till att använda operatorn >>> :

static C1 Test1(C1 x, int y) => x >>> y;

Foreach-uppräknare som referensstruct

Introducerades i .NET SDK 6.0.300, Visual Studio 2022 version 17.2. En uppräkningsstruktur av typen ref struct rapporterar ett fel om språkversionen är inställd på 7.3 eller tidigare.

Detta åtgärdar ett fel där funktionen stöds i nyare kompilatorer som riktar in sig på en version av C# innan den stöds.

Möjliga lösningar är:

  1. ref struct Ändra typen till en struct eller class typ.
  2. Uppgradera elementet <LangVersion> till 7.3 eller senare.

Async foreach föredrar mönsterbaserat DisposeAsync framför en explicit implementering av ett gränssnitt IAsyncDisposable.DisposeAsync()

Introducerades i .NET SDK 6.0.300, Visual Studio 2022 version 17.2. En asynkron foreach föredrar att binda med en mönsterbaserad DisposeAsync() metod snarare än IAsyncDisposable.DisposeAsync().

Till exempel kommer DisposeAsync() att väljas, istället för IAsyncEnumerator<int>.DisposeAsync()-metoden på 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
}

Den här ändringen åtgärdar en specifikationsöverträdelse där den offentliga DisposeAsync metoden visas på den deklarerade typen, medan den explicita gränssnittsimplementeringen endast visas med hjälp av en referens till gränssnittstypen.

Du kan lösa det här felet genom att ta bort den mönsterbaserade DisposeAsync metoden från din typ.

Tillåt inte konverterade strängar som standardargument

Introducerades i .NET SDK 6.0.300, Visual Studio 2022 version 17.2. C#-kompilatorn skulle acceptera felaktiga standardargumentvärden som innebär en referenskonvertering av en strängkonstant och genereras null som konstantvärdet i stället för det standardvärde som anges i källan. I Visual Studio 17.2 blir detta ett fel. Se roslyn#59806.

Den här ändringen åtgärdar en specifikationsöverträdelse i kompilatorn. Standardargumenten måste vara kompileringstidskonstanter. Tidigare versioner tillät följande kod:

void M(IEnumerable<char> s = "hello")

Föregående deklaration krävde en konvertering från string till IEnumerable<char>. Kompilatorn tillät den här konstruktionen och skulle generera null som värdet för argumentet. Föregående kod genererar ett kompilatorfel från och med 17.2.

Om du vill kringgå den här ändringen kan du göra någon av följande ändringar:

  1. Ändra parametertypen så att ingen konvertering krävs.
  2. Ändra värdet för standardargumentet till null för att återställa det tidigare beteendet.

Det kontextuella nyckelordet var som en explicit lambda-returtyp

Introducerades i .NET SDK 6.0.200, Visual Studio 2022 version 17.1. Det går inte att använda den kontextuella nyckelordsvargen som en explicit lambda-returtyp.

Den här ändringen möjliggör potentiella framtida funktioner genom att säkerställa att var förblir den naturliga typen för returtypen för ett lambda-uttryck.

Du kan stöta på det här felet om du har en typ med namnet var och definierar ett lambda-uttryck med en explicit returtyp ( var typen).

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

Lösningarna omfattar följande ändringar:

  1. Använd @var som returtyp.
  2. Ta bort den explicita returtypen så att kompilatorn avgör returtypen.

Interpolerade stränghanterare och indexeringsinitiering

Introducerades i .NET SDK 6.0.200, Visual Studio 2022 version 17.1. Indexerare som tar en interpolerad stränghanterare och kräver mottagaren som indata för konstruktorn kan inte användas i en objektinitierare.

Den här ändringen tillåter inte ett edge-scenario där indexerarens initiatorer använder en interpolerad stränghanterare och den interpolerade stränghanteraren tar indexerarens mottagare som en parameter i konstruktorn. Anledningen till den här ändringen är att det här scenariot kan leda till åtkomst till variabler som ännu inte har initierats. Tänk på det här exemplet:

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

Lösningarna omfattar följande ändringar:

  1. Ta bort mottagartypen från den interpolerade stränghanteraren.
  2. Ändra argumentet till indexeraren till en string

ref, readonly ref, in, out är inte tillåtna som parametrar eller retur på metoder endast med icke hanterade anropare

Introducerades i .NET SDK 6.0.200, Visual Studio 2022 version 17.1.ref/ref readonly/in/out får inte användas vid retur/parametrar för en metod som tillskrivs UnmanagedCallersOnly.

Den här ändringen är en felkorrigering. Returvärden och parametrar är inte blittable. Att skicka argument eller returnera värden med referens kan orsaka odefinierat beteende. Ingen av följande deklarationer kompileras:

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'.

Lösningen är att ta bort by-referensmodifieraren.

Längd, Antal antas vara icke-negativa i mönster

Introducerades i .NET SDK 6.0.200, Visual Studio 2022 version 17.1.Length och Count egenskaper för räknarbara och indexerbara typer antas vara icke-negativa för undersumtion och fullständighetsanalys av mönster och växlar. Dessa typer kan användas med implicita indexindexerare och listmönster.

Length och Count egenskaperna, även om de är angivna som int, antas vara icke-negativa när man analyserar mönster. Tänk på den här exempelmetoden:

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
}

Före 17.1 var den första switcharmen, som testade om Count var negativ, nödvändig för att undvika en varning om att inte alla möjliga värden täcktes. Från och med 17.1 genererar den första växelarmen ett kompilatorfel. Lösningen är att ta bort växelarmarna som lagts till för de ogiltiga fallen.

Den här ändringen gjordes som en del av att lägga till listmönster. Bearbetningsreglerna är mer konsekventa om varje användning av en Length eller Count -egenskap i en samling betraktas som icke-negativ. Du kan läsa mer information om ändringen i språkdesignproblemet.

Lösningen är att ta bort strömbrytarens armar med oåtkomliga förhållanden.

För att lägga till fältinitierare i en struct krävs en uttryckligen deklarerad konstruktor

Introducerades i .NET SDK 6.0.200, Visual Studio 2022 version 17.1.struct typdeklarationer med fältinitierare måste innehålla en uttryckligen deklarerad konstruktor. Dessutom måste alla fält definitivt tilldelas i struct instanskonstruktorer som inte har en : this() initialiserare, så alla tidigare otilldelade fält måste tilldelas från den tillagda konstruktorn eller från fältinitierare. Se dotnet/csharplang#5552, dotnet/roslyn#58581.

Det finns två sätt att initiera en variabel till dess standardvärde i C#: new() och default. För klasser är skillnaden tydlig eftersom new skapar en ny instans och default returnerar null. Skillnaden är mer subtil för structs eftersom structs för defaultreturnerar en instans med varje fält/egenskap inställd på sin egen standard. Vi har lagt till fältinitierare för structs i C# 10. Fältinitierare körs endast när en uttryckligen deklarerad konstruktor körs. De körs inte när du använder default eller skapar en matris av någon struct typ.

I 17.0, om det finns fältinitierare men inga deklarerade konstruktorer, syntetiseras en parameterlös konstruktor som kör fältinitierare. Det innebar dock att lägga till eller ta bort en konstruktordeklaration kan påverka om en parameterlös konstruktor syntetiseras och kan därför ändra beteendet new()för .

För att lösa problemet syntetiserar kompilatorn inte längre en parameterlös konstruktor i .NET SDK 6.0.200 (VS 17.1). Om en struct innehåller fältinitierare och inga explicita konstruktorer genererar kompilatorn ett fel. Om en struct har fältinitierare måste den deklarera en konstruktor, eftersom fältinitierarna annars aldrig körs.

Dessutom måste alla fält som inte har fältinitierare tilldelas i varje struct konstruktor om inte konstruktorn har en : this() initialiserare.

Till exempel:

struct S // error CS8983: A 'struct' with field initializers must include an explicitly declared constructor.
{
    int X = 1; 
    int Y;
}

Lösningen är att deklarera en konstruktor. Om fält inte tidigare har tilldelats kan den här konstruktorn, och ofta kommer att vara, en tom parameterlös konstruktor.

struct S
{
    int X = 1;
    int Y;

    public S() { Y = 0; } // ok
}

Formatspecificerare får inte innehålla klammerparenteser

Introducerades i .NET SDK 6.0.200, Visual Studio 2022 version 17.1. Formatspecificerare i interpolerade strängar får inte innehålla klammerparenteser (antingen { eller }). I tidigare versioner {{ tolkades som en undantagen { och }} tolkades som ett undantaget } tecken i formatspecificeraren. Nu avslutas interpoleringen av det första } teckentecknet i en formatspecificerare, och alla { tecken är ett fel.

Detta gör att interpolerad strängbearbetning överensstämmer med bearbetningen för System.String.Format:

using System;
Console.WriteLine($"{{{12:X}}}");
//prints now: "{C}" - not "{X}}"

X är formatet för versaler hexadecimalt och C är hexadecimalt värde för 12.

Lösningen är att ta bort de extra klammerparenteserna i formatsträngen.

Du kan lära dig mer om den här ändringen i det associerade roslyn-problemet.

Typer kan inte namnges required

Introducerades i Visual Studio 2022 version 17.3. Från och med C# 11 kan typer inte namnges required. Kompilatorn rapporterar ett fel om alla sådana typnamn. Om du vill kringgå detta måste typnamnet och alla användningar vara undantagna med en @:

class required {} // Error CS9029
class @required {} // No error

Detta gjordes som required nu är en medlemsmodifierare för egenskaper och fält.

Du kan läsa mer om den här ändringen i det associerade csharplang-problemet.