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 .NET 6 general release (.NET SDK Version 6.0.100) bis .NET 7 General Release (.NET SDK Version 7.0.100) aufgeführt.
Alle Locals von Einschränkungstypen sind in asynchronen Methoden unzulässig
Eingeführt in Visual Studio 2022, Version 17.6p1
Locals von Einschränkungstypen sind in asynchronen Methoden unzulässig. In früheren Versionen konnte der Compiler jedoch einige implizit deklarierte Lokale nicht bemerken. Zum Beispiel in foreach oder using Anweisungen oder Dekonstruktionen.
Jetzt sind solche implizit deklarierten lokalen Variablen ebenfalls unzulässig.
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")
}
}
Siehe https://github.com/dotnet/roslyn/pull/66264.
Zeiger müssen sich immer in unsicheren Kontexten befinden.
Eingeführt in Visual Studio 2022, Version 17.6
In früheren SDKs würde der Compiler gelegentlich Orte zulassen, an denen Zeiger referenziert werden könnten, ohne diese Position explizit als unsicher zu markieren.
Nun muss der unsafe Modifizierer vorhanden sein.
So sollte beispielsweise using Alias = List<int*[]>; zu using unsafe Alias = List<int*[]>; geändert werden, um legal zu sein.
Eine Verwendung wie void Method(Alias a) ... sollte in unsafe void Method(Alias a) ... geändert werden.
Die Regel ist bedingungslos, mit Ausnahme von using Alias-Deklarationen (die vor C# 12 keine Möglichkeit für einen unsafe-Modifikator boten).
Bei using Deklarationen wird die Regel nur wirksam, wenn die Sprachversion als C# 12 oder höher ausgewählt wird.
System.TypedReference wird als verwaltet angesehen
Eingeführt in Visual Studio 2022, Version 17.6
Der Typ System.TypedReference wird als verwaltet betrachtet.
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-Sicherheitsfehler haben keine Auswirkungen auf die Konversion von Lambda-Ausdrücken in Delegaten
Eingeführt in Visual Studio 2022, Version 17.5
Ref-Sicherheitsfehler, die in einem Lambda Body geliefert werden, haben keinen Einfluss mehr darauf, ob der Lambda Ausdruck in einen Delegaten Typ konvertierbar ist. Diese Änderung kann sich auf die Überlastungsauflösung auswirken.
Im folgenden Beispiel ist der Aufruf von M(x => ...) mit Visual Studio 17.5 mehrdeutig, weil sowohl M(D1) als auch M(D2) jetzt als anwendbar gelten, obwohl der Aufruf von F(ref x, ref y) innerhalb des Lambda-Bodys zu einem Ref Safety mit M(D1) führt (siehe die Beispiele in d1 und d2 zum Vergleich). Zuvor war der Aufruf eindeutig an M(D2) gebunden, weil die Überladung M(D1) als nicht anwendbar angesehen wurde.
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;
};
}
}
Um die Änderungen bei der Überladungsauflösung zu umgehen, verwenden Sie explizite Typen für die Lambda-Parameter oder Delegaten.
// 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;
});
Raw Zeichenfolge Interpolationen am Anfang der Zeile.
Eingeführt in Visual Studio 2022, Version 17.5
In .NET SDK 7.0.100 oder früher war Folgendes falsch zulässig:
var x = $"""
Hello
{1 + 1}
World
""";
Dies hat gegen die Regel verstoßen, dass der Zeileninhalt (einschließlich des Beginns einer Interpolation) mit demselben Leerzeichen wie die letzte """; Zeile beginnen muss. Es ist jetzt erforderlich, dass die oben genannten Schreiben wie folgt erfolgen:
var x = $"""
Hello
{1 + 1}
World
""";
Abgeleiteter Delegierungstyp für Methoden enthält Standardparameterwerte und params-Modifikator
Eingeführt in Visual Studio 2022, Version 17.5
In .NET SDK 7.0.100 oder früher ignorierten von Methoden abgeleitete Delegatentypen Standardparameterwerte und params-Modifikatoren, wie im folgenden Code gezeigt:
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 });
In .NET SDK 7.0.200 oder höher werden solche Methoden als anonyme synthetisierte Delegattypen mit denselben Standardparameterwerten und params Modifizierern abgeleitet.
Diese Änderung kann den obigen Code wie unten gezeigt unterbrechen:
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 });
Weitere Informationen zu dieser Änderung finden Sie im zugehörigen Vorschlag.
Zum Zweck der definitiven Zuordnungsanalyse werden Aufrufe asynchroner lokaler Funktionen nicht mehr als wartend betrachtet.
Eingeführt in Visual Studio 2022, Version 17.5
Zum Zweck der endgültigen Zuordnungsanalyse werden Aufrufe einer asynchronen lokalen Funktion nicht mehr als erwartet behandelt und daher wird die lokale Funktion nicht als vollständig ausgeführt betrachtet. Siehe https://github.com/dotnet/roslyn/issues/43697 für die Begründung.
Der folgende Code wird nun einen eindeutigen Zuordnungsfehler melden:
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-Knoten für Attribute sind jetzt IAttributeOperation-Knoten.
Eingeführt in Visual Studio 2022, Version 17.5, .NET SDK, Version 7.0.200
In früheren Versionen des Compilers war der IOperation-Baum für ein Attribut mit einem INoneOperation-Knoten verwurzelt.
Wir haben native Unterstützung für Attribute hinzugefügt, was bedeutet, dass die Wurzel des Baumes jetzt ein IAttributeOperation ist. Einige Analyzer, einschließlich älterer Versionen der .NET SDK-Analyzer, erwarten diese Baumform nicht und warnen fälschlicherweise (oder möglicherweise gar nicht), wenn sie darauf stoßen. Die Lösungen hierfür sind:
- Aktualisieren Sie ihre Analyseversion, falls möglich. Wenn Sie das .NET SDK oder ältere Versionen von Microsoft.CodeAnalysis.FxCopAnalyzers verwenden, aktualisieren Sie auf Microsoft.CodeAnalysis.NetAnalyzers 7.0.0-preview1.22464.1 oder höher.
- Unterdrücken Sie alle falsch positiven Ergebnisse der Analyse, bis sie mit einer Version aktualisiert werden können, die diese Änderung berücksichtigt.
Typentests für ref Strukturen werden nicht unterstützt.
Eingeführt in Visual Studio 2022, Version 17.4
Wenn ein ref Strukturtyp in einem Operator "is" oder "as" verwendet wird, meldete der Compiler zuvor in einigen Szenarien fälschlicherweise eine Warnung, dass der Typtest zur Laufzeit immer fehlschlägt, wodurch die tatsächliche Typüberprüfung weggelassen und zu einem falschen Verhalten geführt wurde. Wenn bei der Ausführung ein falsches Verhalten möglich war, erzeugt der Compiler stattdessen einen Fehler.
ref struct G<T>
{
public void Test()
{
if (this is G<int>) // Will now produce an error, used to be treated as always `false`.
{
Nicht verwendete Ergebnisse von ref local sind Ableitungen.
Eingeführt in Visual Studio 2022, Version 17.4
Wenn eine refGebietsschema-Variable durch einen Wert referenziert wird, das Ergebnis aber nicht verwendet wird (wie z. B. die Zuweisung zu einem Discard), wurde das Ergebnis bisher ignoriert. Der Compiler dereferenziert nun diese lokale Variable, um sicherzustellen, dass alle Nebeneffekte beachtet werden.
ref int local = Unsafe.NullRef<int>();
_ = local; // Will now produce a `NullReferenceException`
Typen können nicht benannt werden. scoped
In Visual Studio 2022, Version 17.4, eingeführt. Ab C# 11 können Typen nicht benannt scopedwerden. Der Compiler meldet einen Fehler bei allen solchen Typnamen. Um dies zu umgehen, müssen der Typname und alle Verwendungen mit einem @ maskiert werden:
class scoped {} // Error CS9056
class @scoped {} // No error
ref scoped local; // Error
ref scoped.nested local; // Error
ref @scoped local2; // No error
Dies wurde gemacht, da scoped jetzt ein Modifikator für Variablendeklarationen ist und nach ref in einem Ref-Typ reserviert wird.
Typen können nicht benannt werden. file
In Visual Studio 2022, Version 17.4, eingeführt. Ab C# 11 können Typen nicht benannt filewerden. Der Compiler meldet einen Fehler bei allen solchen Typnamen. Um dies zu umgehen, müssen der Typname und alle Verwendungen mit einem @ maskiert werden:
class file {} // Error CS9056
class @file {} // No error
Da file jetzt ein Modifizierer für Typdeklarationen ist, wurde dies so gemacht.
Weitere Informationen zu dieser Änderung finden Sie im zugeordneten Csharplang-Problem.
Erforderliche Leerzeichen in #line span Direktiven
Eingeführt in .NET SDK 6.0.400, Visual Studio 2022, Version 17.3.
Als die #line Span-Direktive in C# 10 eingeführt wurde, war kein bestimmter Abstand erforderlich.
Dies wäre beispielsweise gültig: #line(1,2)-(3,4)5"file.cs".
In Visual Studio 17.3 erfordert der Compiler Leerzeichen vor der ersten Klammer, dem Zeichenoffset und dem Dateinamen.
Daher kann das obige Beispiel nicht analysiert werden, es sei denn, Leerzeichen werden hinzugefügt: #line (1,2)-(3,4) 5 "file.cs".
Geprüfte Operatoren auf System.IntPtr und System.UIntPtr
Eingeführt in .NET SDK 7.0.100, Visual Studio 2022, Version 17.3.
Wenn die Plattform numerischeIntPtr und UIntPtr Typen unterstützt (wie durch das Vorhandensein von System.Runtime.CompilerServices.RuntimeFeature.NumericIntPtr angegeben), werden die integrierten Operatoren auf diese zugrunde liegenden Typen von nint und nuint angewendet.
Dies bedeutet, dass IntPtr und UIntPtr auf solchen Plattformen über integrierte checked-Operatoren verfügen, die nun bei einem Überlauf auslösen können.
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ögliche Umgehungen sind:
- Kontext angeben
unchecked - Downgrade auf eine Plattform/TFM ohne numerische
IntPtr/UIntPtrTypen
Außerdem werden implizite Konvertierungen zwischen IntPtr/UIntPtr und anderen numerischen Typen als Standardkonvertierungen auf solchen Plattformen behandelt. Dies kann sich in einigen Fällen auf die Überlastungsauflösung auswirken.
Diese Änderungen können zu verhaltensbedingten Änderungen führen, wenn der Benutzercode von Überlaufausnahmen in einem deaktivierten Kontext abhängig war oder wenn in einem überprüften Kontext keine Überlaufausnahmen erwartet wurden. Ein Analyzer wurde in 7.0 hinzugefügt , um solche Verhaltensänderungen zu erkennen und geeignete Maßnahmen zu ergreifen. Der Analyzer erstellt Diagnosen von potenziellen Verhaltensänderungen, die standardmäßig als Info-Schweregrad vorliegen, aber über editorconfig zu Warnungen aktualisiert werden können.
Hinzufügung von System.UIntPtr und System.Int32
Eingeführt in .NET SDK 7.0.100, Visual Studio 2022, Version 17.3.
Wenn die Plattform numerischeIntPtr und UIntPtr Typen unterstützt (wie durch das Vorhandensein von System.Runtime.CompilerServices.RuntimeFeature.NumericIntPtr), kann der in +(UIntPtr, int) definierte Operator System.UIntPtr nicht mehr verwendet werden.
Fügen Sie stattdessen Ausdrücke der Typen System.UIntPtr und System.Int32 hinzu, was zu einem Fehler führt:
UIntPtr M(UIntPtr x, int y)
{
return x + y; // error: Operator '+' is ambiguous on operands of type 'nuint' and 'int'
}
Mögliche Umgehungen sind:
- Verwenden Sie die
UIntPtr.Add(UIntPtr, int)Methode:UIntPtr.Add(x, y) - Wenden Sie einen ungeprüften Cast auf den Typ
nuintauf den zweiten Operanden an:x + unchecked((nuint)y)
Nameof-Operator in einem Attribut einer Methode oder lokalen Funktion
Eingeführt in .NET SDK 6.0.400, Visual Studio 2022, Version 17.3.
Wenn die Sprachversion C# 11 oder höher ist, bringt ein nameof-Operator innerhalb eines Attributs einer Methode die Typparameter dieser Methode in den Geltungsbereich. Das gleiche gilt für lokale Funktionen.
Ein nameof-Operator in einem Attribut auf einer Methode, deren Typparameter oder Parameter bringt die Parameter dieser Methode in den Bereich. Das gleiche gilt für lokale Funktionen, Lambdas, Stellvertretungen und Indexer.
Diese werden jetzt zum Beispiel als Fehler angesehen:
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ögliche Umgehungen sind:
- Benennen Sie den Typparameter oder Parameter um, um zu vermeiden, dass der Name aus dem äußeren Bereich überlagert wird.
- Verwenden Sie ein Zeichenfolgenliteral anstelle des
nameof-Operators.
Kann einen out-Parameter nicht per Referenz zurückgeben
Eingeführt in .NET SDK 7.0.100, Visual Studio 2022, Version 17.3.
Bei der Sprachversion C# 11 oder höher oder mit .NET 7.0 oder höher kann kein out Parameter durch Verweis zurückgegeben werden.
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ögliche Umgehungen sind:
Verwenden Sie
System.Diagnostics.CodeAnalysis.UnscopedRefAttribute, um die Referenz als nicht abgedeckt zu markieren.static ref T ReturnOutParamByRef<T>([UnscopedRef] out T t) { t = default; return ref t; // ok }Ändern Sie die Methodensignatur, um den Parameter mit
refzu übergeben.static ref T ReturnRefParamByRef<T>(ref T t) { t = default; return ref t; // ok }
Instanz-Methode auf ref struct kann nicht abgedeckte ref Parameter erfassen
Eingeführt in .NET SDK 7.0.100, Visual Studio 2022, Version 17.4.
Bei der Sprachversion C# 11 oder höher oder mit .NET 7.0 oder höher wird davon ausgegangen, dass ein ref struct-Instanzmethodenaufruf unscoped-ref- oder in-Parameter erfasst.
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) { }
}
Eine mögliche Problemumgehung besteht darin, den Parameter als ref oder in zu deklarieren, wenn der ref struct oder scoped ref Parameter nicht in der scoped in Instanzmethode erfasst wird.
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) { }
}
Methode ref struct return Escape-Analyse hängt von ref Escape von ref Argumenten ab
Eingeführt in .NET SDK 7.0.100, Visual Studio 2022, Version 17.4.
Mit der Sprachversion C# 11 oder höher oder mit .NET 7.0 oder höher ist ein ref structRückgabewert eines Methodenaufrufs, entweder als Rückgabewert oder in einem outParameter, nur dann safe-to-escape, wenn alle refund inArgumente des Methodenaufrufs ref-safe-to-escape sind.
Die in Argumente können implizite Standardwerte enthalten.
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();
}
Eine mögliche Lösung, wenn das ref- oder in-Argument nicht im ref struct-Rückgabewert erfasst wird, besteht darin, den Parameter als scoped ref oder scoped in zu deklarieren.
static R CannotCaptureArg(scoped ref int i) => new R();
static R Create()
{
int i = 0;
return CannotCaptureArg(ref i); // ok
}
ref bis ref struct Argument gilt als nicht abgedeckt in __arglist
Eingeführt in .NET SDK 7.0.100, Visual Studio 2022, Version 17.4.
Mit der Sprachversion C# 11 oder höher oder mit .NET 7.0 oder höher wird ein ref zu einem ref struct Typ als nicht abgedeckte Referenz betrachtet, wenn er als Argument an __arglist übergeben wird.
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
}
}
Rechtsverschiebungs-Operator ohne Vorzeichen
Eingeführt in .NET SDK 6.0.400, Visual Studio 2022, Version 17.3. Die Sprache hat Unterstützung für einen Operator "Unsigned Right Shift" (>>>) hinzugefügt.
Dies verhindert, dass Methoden, die benutzerdefinierte „Unsigned Right-Shift-Operatoren“ implementieren, als reguläre Methoden konsumiert werden können.
Beispielsweise gibt es eine vorhandene Bibliothek, die in einer anderen Sprache (außer VB oder C#) entwickelt wurde, die einen benutzerdefinierten Operator "Unsigned Right Shift" für den Typ C1verfügbar macht.
Der folgende Code wurde früher erfolgreich kompiliert.
static C1 Test1(C1 x, int y) => C1.op_UnsignedRightShift(x, y); //error CS0571: 'C1.operator >>>(C1, int)': cannot explicitly call operator or accessor
Eine mögliche Problemumgehung besteht darin, zur Verwendung >>> des Operators zu wechseln:
static C1 Test1(C1 x, int y) => x >>> y;
Foreach-Enumerator als Referenzstruktur
Eingeführt in .NET SDK 6.0.300, Visual Studio 2022, Version 17.2. Eine foreach Verwendung eines Referenzstrukturenumeratortyps meldet einen Fehler, wenn die Sprachversion auf 7.3 oder früher festgelegt ist.
Dadurch wird ein Fehler behoben, bei dem das Feature in neueren Compilern für eine Version von C# vor seiner Unterstützung unterstützt wurde.
Mögliche Umgehungen sind:
- Ändern Sie den
ref structTyp in einenstructoderclasseinen Typ. - Aktualisieren Sie das
<LangVersion>Element auf 7.3 oder höher.
Async foreach bevorzugt eine auf Mustern basierende DisposeAsync Schnittstelle gegenüber einer expliziten Implementierung von IAsyncDisposable.DisposeAsync()
Eingeführt in .NET SDK 6.0.300, Visual Studio 2022, Version 17.2. Eine asynchrone foreach Methode bevorzugt die Bindung mithilfe einer musterbasierten DisposeAsync() Methode anstelle von IAsyncDisposable.DisposeAsync().
So wird z.B. die DisposeAsync()-Methode ausgewählt und nicht die IAsyncEnumerator<int>.DisposeAsync()-Methode auf 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
}
Diese Änderung behebt eine Spezifikationsverletzung, bei der die öffentliche DisposeAsync Methode für den deklarierten Typ sichtbar ist, während die explizite Schnittstellenimplementierung nur mithilfe eines Verweises auf den Schnittstellentyp sichtbar ist.
Um diesen Fehler zu umgehen, entfernen Sie die musterbasierte DisposeAsync Methode aus Ihrem Typ.
Nicht zulassen, dass konvertierte Zeichenfolgen als Standardargument verwendet werden
Eingeführt in .NET SDK 6.0.300, Visual Studio 2022, Version 17.2. Der C#-Compiler akzeptiert falsche Standardwerte, die eine Verweiskonvertierung einer Zeichenfolgenkonstante enthalten, und würde als Konstantenwert anstelle des in der Quelle angegebenen Standardwerts ausgegeben null . In Visual Studio 17.2 wird dies zu einem Fehler. Siehe roslyn#59806.
Diese Änderung behebt eine Spezifikationsverletzung im Compiler. Standardargumente müssen Kompilierungszeitkonstanten sein. In früheren Versionen war der folgende Code zulässig:
void M(IEnumerable<char> s = "hello")
Die vorangehende Deklaration erforderte eine Konvertierung von string zu IEnumerable<char>. Der Compiler hat dieses Konstrukt zugelassen und würde null als Wert des Arguments ausgeben. Der vorangehende Code erzeugt einen Compilerfehler ab 17.2.
Um diese Änderung zu umgehen, können Sie eine der folgenden Änderungen vornehmen:
- Ändern Sie den Parametertyp so, dass keine Konvertierung erforderlich ist.
- Ändern Sie den Wert des Standardarguments auf
null, um das vorherige Verhalten wiederherzustellen.
Das kontextbezogene Schlüsselwort var als expliziter Lambda-Rückgabetyp
Eingeführt in .NET SDK 6.0.200, Visual Studio 2022, Version 17.1. Der Kontextwort var kann nicht als expliziter Lambda-Rückgabetyp verwendet werden.
Diese Änderung ermöglicht potenzielle zukünftige Features , indem sichergestellt wird, dass der var natürliche Typ für den Rückgabetyp eines Lambda-Ausdrucks bleibt.
Dieser Fehler kann auftreten, wenn Sie einen Typ mit dem Namen var haben und einen Lambda-Ausdruck mit einem expliziten Rückgabetyp var (des Typs) definieren.
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
{
}
Umgehungen umfassen die folgenden Änderungen:
-
@varals Rückgabetyp verwenden. - Entfernen Sie den expliziten Rückgabetyp, damit der Compiler den Rückgabetyp bestimmt.
Interpolierte Zeichenfolgenhandler und Indexerinitialisierung
Eingeführt in .NET SDK 6.0.200, Visual Studio 2022, Version 17.1. Indexer, die einen interpolierten Zeichenfolgenhandler verwenden und den Empfänger als Eingabe für den Konstruktor benötigen, können nicht in einem Objektinitialisierer verwendet werden.
Diese Änderung verbietet ein Randfallszenario, in dem Indexer-Initialisierer einen interpolierten Zeichenfolgen-Handler verwenden, und der interpolierte Zeichenfolgen-Handler den Indexer-Empfänger als Parameter des Konstruktors verwendet. Der Grund für diese Änderung ist, dass dieses Szenario dazu führen kann, auf Variablen zuzugreifen, die noch nicht initialisiert wurden. Betrachten Sie dieses Beispiel:
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) {}
}
Umgehungen umfassen die folgenden Änderungen:
- Entfernen Sie den Empfängertyp aus dem interpolierten Zeichenfolgenhandler.
- Ändern Sie das Argument zum Indexer in ein
string
ref, readonly ref, in, out nicht als Parameter oder Rückgabewert bei Methoden mit nicht verwalteten Aufrufern möglich
Eingeführt in .NET SDK 6.0.200, Visual Studio 2022, Version 17.1.ref/ref readonly/in/out dürfen nicht für Rückgabewerte/Parameter einer Methode verwendet werden, der UnmanagedCallersOnly zugeschrieben ist.
Diese Änderung ist ein Fehlerkorrektur. Rückgabewerte und Parameter sind nicht ausblendbar. Das Übergeben von Argumenten oder Rückgabewerten nach Verweis kann zu einem nicht definierten Verhalten führen. Keine der folgenden Deklarationen wird kompiliert:
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'.
Die Abhilfe besteht darin, den Modifikator by reference zu entfernen.
Länge, Anzahl wird in Mustern als nicht-negativ angenommen
Eingeführt in .NET SDK 6.0.200, Version 17.1 von Visual Studio 2022.Length und Count Eigenschaften von zählbaren und indizierbaren Typen werden als nicht-negativ angenommen für die Subsumptions- und Exhaustivitätsanalyse von Mustern und Switches.
Diese Typen können mit impliziten Indexindexer- und Listenmustern verwendet werden.
Die Eigenschaften Length und Count werden als nicht negativ angenommen, selbst wenn sie als int typisiert sind, wenn Muster analysiert werden. Betrachten Sie diese Beispielmethode:
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
}
Vor Version 17.1 war es notwendig, den ersten Schalterarm, der prüfte, ob Count negativ ist, zu testen, um eine Warnung zu vermeiden, dass nicht alle möglichen Werte abgedeckt sind. Ab 17.1 generiert der erste Schalterarm einen Compilerfehler. Die Abhilfe besteht darin, die für die ungültigen Fälle hinzugefügten Switch-Arme zu entfernen.
Diese Änderung wurde im Rahmen des Hinzufügens von Listenmustern vorgenommen. Die Verarbeitungsregeln sind konsistenter, wenn jede Verwendung einer Length- oder Count-Eigenschaft in einer Sammlung als nicht negativ betrachtet wird. Weitere Informationen zur Änderung des Sprachdesign-Themas finden Sie.
Die Abhilfe besteht darin, die Switch-Arme mit unerreichbaren Bedingungen zu entfernen.
Zum Hinzufügen von Feldinitialisierern zu einer Struktur ist ein explizit deklarierter Konstruktor erforderlich.
Eingeführt in .NET SDK 6.0.200, Visual Studio 2022, Version 17.1.struct Typdeklarationen mit Feldinitialisierern müssen einen explizit deklarierten Konstruktor enthalten. Darüber hinaus müssen alle Felder definitiv in struct Instanzkonstruktoren zugewiesen werden, die keinen : this() Initialisierer besitzen, sodass zuvor nicht zugewiesene Felder aus dem hinzugefügten Konstruktor oder aus Feldinitialisierern zugewiesen werden müssen. Siehe dotnet/csharplang#5552, dotnet/roslyn#58581.
Es gibt zwei Möglichkeiten, eine Variable mit dem Standardwert in C# zu initialisieren: new() und default. Für Klassen ist der Unterschied offensichtlich, da new eine neue Instanz erstellt und defaultnull zurückgibt. Bei Structs ist der Unterschied subtiler, da Structs für default eine Instanz zurückgeben, bei der jedes Feld/Eigenschaftsset auf seine eigene Voreinstellung festgelegt ist. Wir haben Feldinitialisierer für Strukturen in C# 10 hinzugefügt. Feldinitialisierer werden nur ausgeführt, wenn ein explizit deklarierter Konstruktor ausgeführt wird. Erheblich ist, dass sie nicht ausgeführt werden, wenn Sie default verwenden oder ein Array eines beliebigen struct Typs erstellen.
Wenn in 17.0 Feldinitialisierer vorhanden sind, aber keine deklarierten Konstruktoren vorhanden sind, wird ein parameterloser Konstruktor synthetisiert, der Feldinitialisierer ausführt. Dies bedeutet jedoch, dass das Hinzufügen oder Entfernen einer Konstruktordeklaration Einfluss darauf haben könnte, ob ein parameterloser Konstruktor synthetisiert wird, und kann infolgedessen das Verhalten von new() ändern.
Um das Problem zu beheben, synthetisiert der Compiler in .NET SDK 6.0.200 (VS 17.1) keinen parameterlosen Konstruktor mehr. Wenn ein struct Feldinitialisierer und keine expliziten Konstruktoren enthält, generiert der Compiler einen Fehler. Wenn ein struct Feldinitialisierer hat, muss es einen Konstruktor deklarieren, weil die Feldinitialisierer andernfalls nie ausgeführt werden.
Darüber hinaus müssen alle Felder, die nicht über Feldinitialisierer verfügen, in jedem struct Konstruktor zugewiesen werden, es sei denn, der Konstruktor verfügt über einen : this() Initialisierer.
Beispiel:
struct S // error CS8983: A 'struct' with field initializers must include an explicitly declared constructor.
{
int X = 1;
int Y;
}
Die Problemumgehung besteht darin, einen Konstruktor zu deklarieren. Sofern Felder zuvor nicht zugewiesen wurden, kann dieser Konstruktor häufig ein leerer, parameterloser Konstruktor sein.
struct S
{
int X = 1;
int Y;
public S() { Y = 0; } // ok
}
Formatbezeichner können keine geschweiften Klammern enthalten
Eingeführt in .NET SDK 6.0.200, Visual Studio 2022, Version 17.1. Formatbezeichner in interpolierten Zeichenfolgen dürfen keine geschweiften Klammern enthalten (entweder { oder }). In früheren Versionen wurde {{ als maskiertes { und }} als maskiertes } Zeichen in der Formatspezifikation interpretiert. Nun endet das erste } Zeichen in einem Formatbezeichner mit der Interpolation, und jedes { Zeichen ist ein Fehler.
Dadurch wird die interpolierte Zeichenfolgenverarbeitung konsistent mit der Verarbeitung für System.String.Format:
using System;
Console.WriteLine($"{{{12:X}}}");
//prints now: "{C}" - not "{X}}"
X ist das Format für die Hexadezimalzahl in Großbuchstaben und C ist der Hexadezimalwert für 12.
Die Abhilfe besteht darin, die zusätzlichen geschweiften Klammern in der Zeichenfolge für das Format zu entfernen.
Weitere Informationen zu dieser Änderung finden Sie in der zugeordneten Roslyn-Problemstellung.
Typen können nicht benannt werden. required
In Visual Studio 2022, Version 17.3, eingeführt. Ab C# 11 können Typen nicht benannt requiredwerden. Der Compiler meldet einen Fehler bei allen solchen Typnamen. Um dies zu umgehen, müssen der Typname und alle Verwendungen mit einem @ maskiert werden:
class required {} // Error CS9029
class @required {} // No error
Dies wurde getan, da required jetzt ein Mitglied-Modifikator für Eigenschaften und Felder ist.
Weitere Informationen zu dieser Änderung finden Sie im zugeordneten Csharplang-Problem.
Roslyn breaking changes