Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
In diesem Dokument werden bekannte Änderungen in Roslyn nach der allgemeinen Version von .NET 9 (.NET SDK Version 9.0.100) bis zur allgemeinen Version von .NET 10 (.NET SDK Version 10.0.100) aufgeführt.
scoped
in einer Lambda-Parameterliste ist jetzt immer ein Modifizierer.
Eingeführt in Visual Studio 2022, Version 17.13
C# 14 bietet die Möglichkeit, eine Lambda-Funktion mit Parametermodifizierern zu schreiben, ohne einen Parametertyp angeben zu müssen: https://github.com/dotnet/csharplang/blob/main/proposals/simple-lambda-parameters-with-modifiers.md
Im Rahmen dieser Arbeit wurde eine bahnbrechende Änderung akzeptiert, bei der scoped
immer als Modifizierer in einem Lambda-Parameter behandelt wird, auch wenn er in der Vergangenheit als Typname akzeptiert wurde. Zum Beispiel:
var v = (scoped scoped s) => { ... };
ref struct @scoped { }
In C# 14 ist dies ein Fehler, da beide scoped
Token als Modifizierer behandelt werden. Die Problemumgehung besteht darin, @
in der Typnamenposition wie folgt zu verwenden:
var v = (scoped @scoped s) => { ... };
ref struct @scoped { }
Span<T>
and ReadOnlySpan<T>
Überladungen sind in mehr Szenarien in C# 14 und neuer anwendbar
Eingeführt in Visual Studio 2022, Version 17.13
C# 14 führt neue eingebaute Span-Konvertierungen und neue Typinferenzregeln ein. Dies bedeutet, dass im Vergleich zu C# 13 unterschiedliche Überladungen gewählt werden könnten, und manchmal könnte ein Mehrdeutigkeits-Kompilierfehler ausgelöst werden, weil eine neue Überladung anwendbar ist, es aber keine einzige beste Überladung gibt.
Das folgende Beispiel zeigt einige Ambiguitäten und mögliche Problemumgehungen.
Beachten Sie, dass eine weitere Abhilfe für API-Autoren darin besteht, die OverloadResolutionPriorityAttribute
zu verwenden.
var x = new long[] { 1 };
Assert.Equal([2], x); // previously Assert.Equal<T>(T[], T[]), now ambiguous with Assert.Equal<T>(ReadOnlySpan<T>, Span<T>)
Assert.Equal([2], x.AsSpan()); // workaround
var y = new int[] { 1, 2 };
var s = new ArraySegment<int>(y, 1, 1);
Assert.Equal(y, s); // previously Assert.Equal<T>(T, T), now ambiguous with Assert.Equal<T>(Span<T>, Span<T>)
Assert.Equal(y.AsSpan(), s); // workaround
A Span<T>
Überladung könnte in C# 14 gewählt werden, wo eine Überladung, die eine Schnittstelle nimmt, die von T[]
(wie zum Beispiel IEnumerable<T>
) wurde in C# 13 gewählt, und das kann zu einer ArrayTypeMismatchException
zur Laufzeit, wenn sie mit einem kovarianten Array verwendet wird:
string[] s = new[] { "a" };
object[] o = s; // array variance
C.R(o); // wrote 1 previously, now crashes in Span<T> constructor with ArrayTypeMismatchException
C.R(o.AsEnumerable()); // workaround
static class C
{
public static void R<T>(IEnumerable<T> e) => Console.Write(1);
public static void R<T>(Span<T> s) => Console.Write(2);
// another workaround:
public static void R<T>(ReadOnlySpan<T> s) => Console.Write(3);
}
Aus diesem Grund, ReadOnlySpan<T>
wird im Allgemeinen vorgezogen gegenüber Span<T>
durch Überlastauflösung in C# 14.
In einigen Fällen kann das zu Kompilierungsunterbrechungen führen, zum Beispiel, wenn es sowohl für Span<T>
als auch für ReadOnlySpan<T>
Überladungen gibt, die beide denselben Spantyp annehmen und zurückgeben.
double[] x = new double[0];
Span<ulong> y = MemoryMarshal.Cast<double, ulong>(x); // previously worked, now compilation error
Span<ulong> z = MemoryMarshal.Cast<double, ulong>(x.AsSpan()); // workaround
static class MemoryMarshal
{
public static ReadOnlySpan<TTo> Cast<TFrom, TTo>(ReadOnlySpan<TFrom> span) => default;
public static Span<TTo> Cast<TFrom, TTo>(Span<TFrom> span) => default;
}
Wenn Sie C# 14 oder neuer verwenden und eine ältere .NET-Version als net10.0
oder das .NET Framework mit einer System.Memory
-Referenz anvisieren, gibt es eine wesentliche Änderung bei Enumerable.Reverse
und Arrays:
int[] x = new[] { 1, 2, 3 };
var y = x.Reverse(); // previously Enumerable.Reverse, now MemoryExtensions.Reverse
Auf net10.0
gibt es Enumerable.Reverse(this T[])
, das Vorrang hat und damit der Bruch vermieden wird.
Ansonsten wird MemoryExtensions.Reverse(this Span<T>)
aufgelöst, was eine andere Semantik hat als Enumerable.Reverse(this IEnumerable<T>)
(das in früheren Versionen von C# 13 und darunter aufgelöst wurde).
Genauer gesagt, die Span
Verlängerung führt die Umkehrung an Ort und Stelle durch und kehrt zurück void
.
Als Abhilfe kann man entweder seine eigene Enumerable.Reverse(this T[])
definieren oder Enumerable.Reverse
ausdrücklich verwenden.
int[] x = new[] { 1, 2, 3 };
var y = Enumerable.Reverse(x); // instead of 'x.Reverse();'
Diagnostik jetzt für musterbasierte Entsorgungsmethode in foreach
Eingeführt in Visual Studio 2022, Version 17.13
Zum Beispiel wird eine veraltete DisposeAsync
Methode nun in await foreach
gemeldet.
await foreach (var i in new C()) { } // 'C.AsyncEnumerator.DisposeAsync()' is obsolete
class C
{
public AsyncEnumerator GetAsyncEnumerator(System.Threading.CancellationToken token = default)
{
throw null;
}
public sealed class AsyncEnumerator : System.IAsyncDisposable
{
public int Current { get => throw null; }
public Task<bool> MoveNextAsync() => throw null;
[System.Obsolete]
public ValueTask DisposeAsync() => throw null;
}
}
Zustand des Enumerator-Objekts bei der Entsorgung auf „nach“ setzen
Eingeführt in Visual Studio 2022, Version 17.13
Der Zustandsautomat für Enumeratoren erlaubte fälschlicherweise die Wiederaufnahme der Ausführung, nachdem der Enumerator entsorgt wurde.
Jetzt, MoveNext()
auf einen entsorgten Enumerator gibt ordnungsgemäß zurück false
ohne weiteren Benutzercode auszuführen.
var enumerator = C.GetEnumerator();
Console.Write(enumerator.MoveNext()); // prints True
Console.Write(enumerator.Current); // prints 1
enumerator.Dispose();
Console.Write(enumerator.MoveNext()); // now prints False
class C
{
public static IEnumerator<int> GetEnumerator()
{
yield return 1;
Console.Write("not executed after disposal")
yield return 2;
}
}
UnscopedRefAttribute
kann nicht mit alten Sicherheitsvorschriften verwendet werden
Eingeführt in Visual Studio 2022, Version 17.13
Die UnscopedRefAttribute
Unbeabsichtigt betroffener Code, der von neuen Roslyn-Compiler-Versionen kompiliert wurde, selbst wenn der Code im Kontext der früheren Ref-Sicherheitsregeln kompiliert wurde (d. h. für C# 10 oder früher mit net6.0 oder früher).
Das Attribut sollte jedoch in diesem Kontext keine Auswirkung haben, und dies ist jetzt behoben.
Code, der zuvor keine Fehler in C# 10 oder früher mit net6.0 oder früher gemeldet hat, kann jetzt nicht kompiliert werden:
using System.Diagnostics.CodeAnalysis;
struct S
{
public int F;
// previously allowed in C# 10 with net6.0
// now fails with the same error as if the [UnscopedRef] wasn't there:
// error CS8170: Struct members cannot return 'this' or other instance members by reference
[UnscopedRef] public ref int Ref() => ref F;
}
Um Missverständnissen vorzubeugen (wenn Sie denken, dass das Attribut eine Wirkung hat, es aber tatsächlich nicht der Fall ist, weil Ihr Code mit den früheren Ref-Sicherheitsregeln kompiliert wurde), wird eine Warnung ausgegeben, wenn das Attribut in C# 10 oder früher mit net6.0 oder früher verwendet wird:
using System.Diagnostics.CodeAnalysis;
struct S
{
// both are errors in C# 10 with net6.0:
// warning CS9269: UnscopedRefAttribute is only valid in C# 11 or later or when targeting net7.0 or later.
[UnscopedRef] public ref int Ref() => throw null!;
public static void M([UnscopedRef] ref int x) { }
}
Microsoft.CodeAnalysis.EmbeddedAttribute
wird bei der Anmeldung validiert
Eingeführt in Visual Studio 2022, Version 17.13
Der Compiler prüft nun die Form von Microsoft.CodeAnalysis.EmbeddedAttribute
, wenn sie im Quelltext deklariert ist. Zuvor hatte der Compiler benutzerdefinierte Deklarationen dieses Attributs zugelassen, aber nur dann, wenn er nicht selbst einen generieren musste. Wir überprüfen jetzt Folgendes:
- Es muss intern sein
- Es muss eine Klasse sein
- Es muss versiegelt sein
- Es muss nicht-statisch sein
- Es muss über einen internen oder öffentlichen parameterlosen Konstruktor verfügen.
- Es muss von System.Attribute erben.
- Sie muss für jede Typdeklaration (Klasse, Struktur, Schnittstelle, Enum oder Delegat) zulässig sein.
namespace Microsoft.CodeAnalysis;
// Previously, sometimes allowed. Now, CS9271
public class EmbeddedAttribute : Attribute {}
Der Ausdruck field
in einem Eigenschaftenaccessor bezieht sich auf das synthetisierte Unterstützungsfeld
Eingeführt in Visual Studio 2022 Version 17.12
Der Ausdruck field
bezieht sich bei Verwendung in einem Eigenschaftenaccessor auf ein synthetisiertes Unterstützungsfeld für die Eigenschaft.
Die Warnung CS9258 wird gezeigt, wenn der Bezeichner in Sprachversion 13 oder früher an ein anderes Symbol gebunden wäre.
Um das Generieren eines synthetisierten Sicherungsfelds zu vermeiden und auf das vorhandene Element zu verweisen, verwenden Sie stattdessen "this.field" oder "@field".
Benennen Sie alternativ das vorhandene Mitglied und den Verweis auf dieses Mitglied um, um einen Konflikt mit field
zu vermeiden.
class MyClass
{
private int field = 0;
public object Property
{
get
{
// warning CS9258: The 'field' keyword binds to a synthesized backing field for the property.
// To avoid generating a synthesized backing field, and to refer to the existing member,
// use 'this.field' or '@field' instead.
return field;
}
}
}
Die Variable mit dem Namen field
ist in einem Eigenschaftsaccessor unzulässig
Eingeführt in Visual Studio 2022 Version 17.14
Der Ausdruck field
bezieht sich bei Verwendung in einem Eigenschaftenaccessor auf ein synthetisiertes Unterstützungsfeld für die Eigenschaft.
Der Fehler CS9272 wird gemeldet, wenn ein lokaler oder ein Parameter einer eingebetteten Funktion mit dem Namen field
in einem Eigenschaftsaccessor deklariert wird.
Um den Fehler zu vermeiden, benennen Sie die Variable um, oder verwenden Sie @field
in der Deklaration.
class MyClass
{
public object Property
{
get
{
// error CS9272: 'field' is a keyword within a property accessor.
// Rename the variable or use the identifier '@field' instead.
int field = 0;
return @field;
}
}
}
record
- und record struct
-Typen können keine Zeigertyp-Mitglieder definieren, auch wenn sie ihre eigenen Equals-Implementierungen bereitstellen.
Eingeführt in Visual Studio 2022 Version 17.14
Die Spezifikation für record class
- und record struct
Typen weist darauf hin, dass zeigertypen als Instanzfelder unzulässig sind.
Dies wurde jedoch nicht ordnungsgemäß erzwungen, wenn der record class
- oder record struct
-Typ eine eigene Implementierung von Equals
definiert hat.
Der Compiler verbietet dies jetzt richtig.
unsafe record struct R(
int* P // Previously fine, now CS8908
)
{
public bool Equals(R other) => true;
}
Das Erstellen von ausführbaren Programmen nur mit Metadaten erfordert einen Einsprungspunkt.
Eingeführt in Visual Studio 2022 Version 17.14
Zuvor war der Einstiegspunkt unbeabsichtigt nicht festgelegt, wenn ausführbare Dateien im Modus „Nur-Metadaten“ (auch als Referenzassemblys bezeichnet) gesendet wurden. Das ist jetzt korrigiert, bedeutet aber auch, dass ein fehlender Eintragspunkt ein Kompilierungsfehler ist:
// previously successful, now fails:
CSharpCompilation.Create("test").Emit(new MemoryStream(),
options: EmitOptions.Default.WithEmitMetadataOnly(true))
CSharpCompilation.Create("test",
// workaround - mark as DLL instead of EXE (the default):
options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary))
.Emit(new MemoryStream(),
options: EmitOptions.Default.WithEmitMetadataOnly(true))
Ebenso kann dies bei Verwendung des Befehlszeilenarguments /refonly
oder der ProduceOnlyReferenceAssembly
MSBuild-Eigenschaft beobachtet werden.
partial
kann kein Rückgabetyp von Methoden sein.
Eingeführt in Visual Studio 2022 Version 17.14
Dank der Sprachfunktion Partielle Ereignisse und Konstruktoren kann sich der partial
Modifizierer an mehreren Stellen befinden und kann daher kein Rückgabetyp sein, es sei denn, er wurde mit dem Escapezeichen versehen:
class C
{
partial F() => new partial(); // previously worked
@partial F() => new partial(); // workaround
}
class partial { }
extension
behandelt als kontextbezogenes Schlüsselwort
In Visual Studio 2022, Version 17.14, eingeführt. Ab C# 14 dient das extension
Schlüsselwort einem speziellen Zweck bei der Kennzeichnung von Erweiterungscontainern.
Dadurch wird geändert, wie der Compiler bestimmte Codekonstrukte interpretiert.
Wenn Sie "extension" anstelle eines Schlüsselworts als Bezeichner verwenden müssen, escapen Sie es mit dem Präfix "@
": "@extension
". Dadurch wird der Compiler aufgefordert, ihn als regulärer Bezeichner anstelle eines Schlüsselworts zu behandeln.
Der Compiler analysiert dies als Erweiterungscontainer und nicht als Konstruktor.
class @extension
{
extension(object o) { } // parsed as an extension container
}
Der Compiler analysiert dies nicht als Methode mit Rückgabetyp extension
.
class @extension
{
extension M() { } // will not compile
}
In Visual Studio 2022, Version 17.15, eingeführt. Der Bezeichner "extension" kann nicht als Typname verwendet werden, sodass Folgendes nicht kompiliert wird:
using extension = ...; // alias may not be named "extension"
class extension { } // type may not be named "extension"
class C<extension> { } // type parameter may not be named "extension"
Partielle Eigenschaften und Ereignisse sind jetzt implizit virtuell und öffentlich
Eingeführt in Visual Studio 2022, Version 17.15
Es wurde eine Inkonsistenz behoben, bei der partielle Schnittstelleneigenschaften und -ereignisse im Gegensatz zu ihren nicht-partiellen Entsprechungen nicht implizit virtual
und public
wären.
Diese Inkonsistenz wird jedoch für partielle Schnittstellenmethoden beibehalten , um eine größere Unterbrechungsänderung zu vermeiden.
Beachten Sie, dass Visual Basic und andere Sprachen, die keine Standardschnittstellenelemente unterstützen, dazu verpflichtet sein werden, implizit virtuelle partial
Schnittstellenmitglieder zu implementieren.
Um das vorherige Verhalten beizubehalten, markieren Sie partial
Schnittstellenmmber explizit als private
(wenn sie keine Barrierefreiheitsmodifizierer haben) und sealed
(wenn sie nicht über den Modifizierer verfügen, der private
impliziert sealed
, und sie verfügen nicht bereits über Modifizierer virtual
oder sealed
).
System.Console.Write(((I)new C()).P); // wrote 1 previously, writes 2 now
partial interface I
{
public partial int P { get; }
public partial int P => 1; // implicitly virtual now
}
class C : I
{
public int P => 2; // implements I.P
}
System.Console.Write(((I)new C()).P); // inaccessible previously, writes 1 now
partial interface I
{
partial int P { get; } // implicitly public now
partial int P => 1;
}
class C : I;
Roslyn breaking changes