Condividi tramite


Modifiche di rilievo in Roslyn dopo .NET 10.0.100 a .NET 11.0.100

Questo documento elenca le modifiche di rilievo note in Roslyn dopo la versione generale di .NET 10 (.NET SDK versione 10.0.100) fino alla versione generale di .NET 11 (.NET SDK versione 11.0.100).

Il contesto sicuro di un'espressione di raccolta di tipo Span/ReadOnlySpan è ora di tipo declaration-block

Introdotto in Visual Studio 2026 versione 18.3

Il compilatore C# ha apportato una modifica importante per rispettare correttamente le regole di sicurezza dei riferimenti nella specifica della funzionalità delle espressioni di raccolta. In particolare, la clausola seguente:

  • Se il tipo di destinazione è un tipo spanSystem.Span<T> o System.ReadOnlySpan<T>, il contesto sicuro per l'espressione di raccolta è il blocco di dichiarazione.

In precedenza, il compilatore usava il membro della funzione safe-context in questa situazione. È stata apportata una modifica per usare il blocco di dichiarazione in base alla specifica. Ciò può causare la visualizzazione di nuovi errori nel codice esistente, ad esempio nello scenario seguente:

scoped Span<int> items1 = default;
scoped Span<int> items2 = default;
foreach (var x in new[] { 1, 2 })
{
    Span<int> items = [x];
    if (x == 1)
        items1 = items; // previously allowed, now an error

    if (x == 2)
        items2 = items; // previously allowed, now an error
}

Se il codice è interessato da questo cambiamento radicale, considerare di utilizzare un tipo di array per le espressioni di raccolta pertinenti.

scoped Span<int> items1 = default;
scoped Span<int> items2 = default;
foreach (var x in new[] { 1, 2 })
{
    int[] items = [x];
    if (x == 1)
        items1 = items; // ok, using 'int[]' conversion to 'Span<int>'

    if (x == 2)
        items2 = items; // ok
}

In alternativa, spostare l'espressione di raccolta in un ambito in cui è consentita l'assegnazione:

scoped Span<int> items1 = default;
scoped Span<int> items2 = default;
Span<int> items = [0];
foreach (var x in new[] { 1, 2 })
{
    items[0] = x;
    if (x == 1)
        items1 = items; // ok

    if (x == 2)
        items2 = items; // ok
}

Vedi anche https://github.com/dotnet/csharplang/issues/9750.

Gli scenari che richiedono al compilatore di sintetizzare un delegato di ritorno ref readonly richiedono ora la disponibilità del tipo System.Runtime.InteropServices.InAttribute.

Introdotto in Visual Studio 2026 versione 18.3

Il compilatore C# ha apportato una modifica di rilievo per generare correttamente i metadati per ref readonly che restituiscono delegati sintetizzati

Ciò può causare la visualizzazione di un "errore CS0518: il tipo predefinito 'System.Runtime.InteropServices.InAttribute' non è definito o importato" nel codice esistente, ad esempio negli scenari seguenti:

var d = this.MethodWithRefReadonlyReturn;
var d = ref readonly int () => ref x;

Se il codice è interessato da questo cambiamento incompatibile, è consigliabile aggiungere un riferimento a un assembly che definisce System.Runtime.InteropServices.InAttribute nel tuo progetto.

Gli scenari che usano ref readonly funzioni locali ora richiedono la disponibilità di tipo System.Runtime.InteropServices.InAttribute.

Introdotto in Visual Studio 2026 versione 18.3

Il compilatore C# ha apportato una modifica di rilievo per generare correttamente i metadati per le funzioni locali che restituiscono ref readonly.

Ciò può causare la visualizzazione di un "errore CS0518: il tipo predefinito 'System.Runtime.InteropServices.InAttribute' non è definito o importato" nel codice esistente, ad esempio nello scenario seguente:

void Method()
{
    ...
    ref readonly int local() => ref x;
    ...
}

Se il codice è interessato da questo cambiamento incompatibile, è consigliabile aggiungere un riferimento a un assembly che definisce System.Runtime.InteropServices.InAttribute nel tuo progetto.

La valutazione dinamica degli &&/|| operatori non è consentita con l'operando sinistro tipizzato in modo statico come interfaccia.

Introdotto in Visual Studio 2026 versione 18.3

Il compilatore C# segnala ora un errore quando un tipo di interfaccia viene usato come operando sinistro di un operatore logico && o || con un dynamic operando destro. In precedenza, il codice veniva compilato per un tipo di interfaccia con true/false operatori, ma falliva in fase di esecuzione con un RuntimeBinderException perché il binder di runtime non è in grado di richiamare gli operatori definiti sulle interfacce.

Questa modifica impedisce un errore di runtime segnalandolo in fase di compilazione. Il messaggio di errore è:

errore CS7083: l'espressione deve essere convertibile in modo implicito in booleano o il relativo tipo 'I1' non deve essere un'interfaccia e deve definire l'operatore 'false'.

interface I1
{
    static bool operator true(I1 x) => false;
    static bool operator false(I1 x) => false;
}

class C1 : I1
{
    public static C1 operator &(C1 x, C1 y) => x;
    public static bool operator true(C1 x) => false;
    public static bool operator false(C1 x) => false;
}

void M()
{
    I1 x = new C1();
    dynamic y = new C1();
    _ = x && y; // error CS7083: Expression must be implicitly convertible to Boolean or its type 'I1' must not be an interface and must define operator 'false'.
}

Se il codice è influenzato da questa modifica interrompente, è consigliabile modificare il tipo statico dell'operando sinistro da un tipo di interfaccia a un tipo di classe concreto o al tipo dynamic:

void M()
{
    I1 x = new C1();
    dynamic y = new C1();
    _ = (C1)x && y; // Valid - uses operators defined on C1
    _ = (dynamic)x && y; // Valid - uses operators defined on C1
}

Vedi anche https://github.com/dotnet/roslyn/issues/80954.

nameof(this.) negli attributi non è consentito

Introdotto in Visual Studio 2026 versione 18.3 e .NET 10.0.200

L'uso della parola chiave this o base all'interno di nameof in un attributo era precedentemente consentito in Roslyn a partire da C# 12 e viene ora correttamente non consentito per corrispondere alla specifica del linguaggio. Questa modifica che causa un'interruzione può essere mitigata rimuovendo this. e accedendo al membro senza il qualificatore.

Vedi anche https://github.com/dotnet/roslyn/issues/82251.

class C
{
    string P;
    [System.Obsolete(nameof(this.P))] // now disallowed
    [System.Obsolete(nameof(P))] // workaround
    void M() { }
}

Analisi di 'with' all'interno di switch-expression-arm

Introdotto in Visual Studio 2026 versione 18.4

Consulta https://github.com/dotnet/roslyn/issues/81837 e https://github.com/dotnet/roslyn/pull/81863

In precedenza, quando viene visualizzato quanto segue, il compilatore considera (X.Y)when come un'espressione cast. In particolare, eseguire il cast dell'identificatore contestuale when in (X.Y):

x switch
{
    (X.Y) when
}

Questo era indesiderato e ciò implicava che un semplice when controllo del modello (come (X.Y) when a > b =>) non analizzava correttamente. Ora, questo viene considerato come un modello (X.Y) costante seguito da un oggetto when clause.

with() è trattato come un elemento di espressione di raccolta negli argomenti di costruzione della raccolta

Introdotto in Visual Studio 2026 versione 18.4

with(...) è utilizzato come elemento in un'espressione di raccolta e, quando LangVersion è impostato su 15 o superiore, è legato come argomenti passati al costruttore o al metodo di fabbrica utilizzato per creare la raccolta, anziché come invocazione di un metodo denominato with.

Per eseguire l'associazione a un metodo denominato with, usare @with invece .

object x, y, z = ...;
object[] items;

items = [with(x, y), z];  // C# 14: call to with() method; C# 15: error args not supported for object[]
items = [@with(x, y), z]; // call to with() method
object with(object a, object b) { ... }