ref readonly
Parameter
Anmerkung
Dieser Artikel ist eine Featurespezifikation. Die Spezifikation dient als Designdokument für das Feature. Es enthält vorgeschlagene Spezifikationsänderungen sowie Informationen, die während des Entwurfs und der Entwicklung des Features erforderlich sind. Diese Artikel werden veröffentlicht, bis die vorgeschlagenen Spezifikationsänderungen abgeschlossen und in die aktuelle ECMA-Spezifikation aufgenommen werden.
Es kann einige Abweichungen zwischen der Featurespezifikation und der abgeschlossenen Implementierung geben. Diese Unterschiede werden in den relevanten Anmerkungen zum Language Design Meeting (LDM) erfasst.
Weitere Informationen zum Prozess für die Aufnahme von Funktions-Speclets in den C#-Sprachstandard finden Sie im Artikel zu den Spezifikationen.
Zusammenfassung
Lassen Sie Regeln für die Änderung der Parameterdeklarationsstelle ref readonly
und die Callsite-Änderung wie folgt zu:
Callsite-Anmerkung | ref Parameter |
ref readonly Parameter |
in Parameter |
out Parameter |
---|---|---|---|---|
ref |
Zulässig | Zulässig | Warnung | Fehler |
in |
Fehler | Zulässig | Zulässig | Fehler |
out |
Fehler | Fehler | Fehler | Zulässig |
Keine Anmerkung | Fehler | Warnung | Zulässig | Fehler |
(Beachten Sie, dass es eine Änderung an den bestehenden Regeln gibt: in
Parameter mit ref
Callsite-Anmerkung erzeugt eine Warnung anstelle eines Fehlers.)
Ändern Sie die Argumentwertregeln wie folgt:
Art des Werts | ref Parameter |
ref readonly Parameter |
in Parameter |
out Parameter |
---|---|---|---|---|
rvalue | Fehler | Warnung | Zulässig | Fehler |
lvalue | Zulässig | Zulässig | Zulässig | Zulässig |
Wo "lvalue" eine Variable bedeutet (also einen Wert mit einem Speicherort; dieser muss nicht schreib- oder zuweisbar sein) und "rvalue" jede Art von Wert.
Motivation
C# 7.2 hat in
-Parameter eingeführt, um schreibgeschützte Verweise zu übergeben.
in
-Parameter ermöglichen sowohl lvalues als auch rvalues und können ohne Anmerkung an der Callsite verwendet werden.
APIs, die Verweise aus ihren Parametern erfassen oder zurückgeben, lassen rvalues jedoch nicht zu und erzwingen auch Hinweise an der Callsite dazu, dass ein Verweis erfasst wird.
ref readonly
-Parameter sind ideal für solche Fälle geeignet, da sie eine Warnung ausgeben, wenn sie mit rvalues oder ohne jegliche Anmerkung an der Callsite verwendet werden.
Darüber hinaus gibt es APIs, die nur schreibgeschützte Verweise benötigen, jedoch
-
ref
-Parameter verwenden, da sie vor der Verfügbarkeit vonin
eingeführt wurden und ein Wechsel zuin
eine disruptive Änderung von Quelle und Binärdatei darstellen würde, z. B.QueryInterface
, oder -
in
Parameter, um schreibgeschützte Verweise zu akzeptieren, obwohl das Übergeben von rvalues an diese nicht wirklich sinnvoll ist, z. B.ReadOnlySpan<T>..ctor(in T value)
oder -
ref
-Parameter, um rvalues nicht zuzulassen, selbst wenn diese die übergebene Referenz nicht verändern, z. B.Unsafe.IsNullRef
.
Diese APIs könnten zu ref readonly
-Parametern migrieren, ohne die Benutzer zu beeinträchtigen.
Detaillierte Informationen zur binären Kompatibilität finden Sie in der vorgeschlagenen Metadatenkodierung.
Insbesondere wäre das Ändern von
-
ref
→ref readonly
lediglich eine disruptive Binär-Änderung für virtuelle Methoden, -
ref
→in
wäre ebenfalls eine disruptive Binär-Änderung für virtuelle Methoden, jedoch keine disruptive Quell-Änderung (da die Regeln so geändert werden, dass lediglich bei derref
Übergabe von Argumenten anin
Parameter gewarnt wird), -
in
→ref readonly
wäre keine disruptive Änderung (aber kein(e) Callsite-Anmerkung oder rvalue würde zu einer Warnung führen),- Beachten Sie, dass dies eine disruptive Quelländerung für Benutzer mit älteren Compilerversionen wäre (da diese
ref readonly
-Parameter alsref
-Parameter interpretieren, diein
oder keine Anmerkung an der Callsite aufheben nicht zulassen) und neue Compilerversionen mitLangVersion <= 11
(für Konsistenz mit älteren Compilerversionen wird der Fehler ausgegeben, dassref readonly
-Parameter nicht unterstützt werden, es sei denn, die entsprechenden Argumente werden mit demref
-Modifizierer übergeben).
- Beachten Sie, dass dies eine disruptive Quelländerung für Benutzer mit älteren Compilerversionen wäre (da diese
Umgekehrt wäre die Änderung
-
ref readonly
→ref
eine potenziell disruptive Quelländerung (es sei denn, es wurden nur dieref
-Callsite-Anmerkung verwendet und nur schreibgeschützte Referenzen als Argumente verwendet), und eine disruptive Binäränderung für virtuelle Methoden, -
ref readonly
→in
wäre keine disruptive Änderung (aber dieref
-Callsite-Anmerkung würde zu einer Warnung führen).
Beachten Sie, dass die oben beschriebenen Regeln auf Methodensignaturen, aber nicht auf Stellvertretungssignaturen angewendet werden.
Das Ändern von ref
zu in
in einer Delegatsignatur kann beispielsweise eine disruptive Quelländerung sein (wenn ein Benutzer eine Methode mit einem ref
-Parameter diesem Delegattyp zuweist, würde dies nach der API-Änderung zu einem Fehler führen).
detaillierter Entwurf
Im Allgemeinen sind die Regeln für ref readonly
-Parameter gleich wie die für in
-Parameter in ihrem Vorschlag , außer wenn sie in diesem Vorschlag explizit geändert werden.
Parameterdeklarationen
Es sind keine Grammatikänderungen erforderlich.
Der Modifizierer ref readonly
ist für Parameter zulässig.
Abgesehen von den normalen Methoden dürfen ref readonly
für Indexerparameter (wie in
, aber im Gegensatz zu ref
) verwendet werden, jedoch nicht für Operatorparameter (wie ref
, aber im Gegensatz zu in
).
Standardwerte sind für ref readonly
-Parameter mit einer Warnung zulässig, da sie dem Übergeben von rvalues entsprechen.
Auf diese Weise können API-Autoren in
-Parameter mit Standardwerten zu ref readonly
-Parametern ändern, ohne eine disruptive Quelländerung zu verursachen.
Prüfungen von Wertarten
Beachten Sie, dass, auch wenn der ref
-Argumentmodifizierer für ref readonly
-Parameter zulässig ist, sich in Bezug auf Wertartüberprüfungen nichts ändert, d. h.,
ref
kann nur mit zuweisbaren Werten verwendet werden.- um schreibgeschützte Verweise zu übergeben, muss stattdessen der Argumentmodifizierer
in
verwendet werden; - um rvalues zu übergeben, darf kein Modifizierer verwendet werden (was zu einer Warnung für
ref readonly
-Parameter führt, wie in der -Zusammenfassung dieses Vorschlagsbeschrieben).
Überladungsauflösung
Die Überladungsauflösung ermöglicht das Mischen von ref
/ref readonly
/in
/ohne Callsite-Anmerkungen und Parameter-Modifizierer wie in der Tabelle in der Zusammenfassung dieses Vorschlags angegeben,, d. h., alle zuässigen und Warnungs-Fälle gelten bei der Überladungsauflösung als mögliche Kandidaten.
Insbesondere gibt es eine Änderung des bestehenden Verhaltens, bei dem Methoden mit dem in
-Parameter mit Aufrufen übereinstimmen, wobei das entsprechende Argument mit ref
markiert ist – diese Änderung hängt von der LangVersion ab.
Die Warnung beim Übergeben eines Arguments ohne Callsite-Modifizierer an einen ref readonly
-Parameter wird jedoch unterdrückt, wenn der Parameter
- der Empfänger in einem Erweiterungsmethodenaufruf ist,
- der implizit als Teil eines benutzerdefinierten Auflistungsinitialisierers oder eines Handlers für interpolierte Zeichenfolgen verwendet wird.
Wert-Überladungen werden gegenüber ref readonly
-Überladungen bevorzugt, wenn kein Argumentmodifizierer vorhanden ist (in
-Parameter zeigen das gleiche Verhalten).
Methodenkonvertierungen
Ebenso werden diese Modifiziere für Konvertierungen von anonymen Funktionen [§10.7] und Methodengruppen [§10.8] als kompatibel betrachtet (aber jede zulässige Konvertierung zwischen verschiedenen Modifizierern führt zu einer Warnung):
- Der
ref readonly
-Parameter der Zielmethode darf mit demin
- oderref
-Parameter des Delegaten übereinstimmen. - Der
in
-Parameter der Zielmethode darf mit demref readonly
- oder, abhängig von der LangVersion, demref
-Parameter des Delegaten übereinstimmen. - Hinweis: Der
ref
-Parameter der Zielmethode darf nicht mit dem -,-,in
- oderref readonly
-Parameter des Delegaten übereinstimmen.
Zum Beispiel:
DIn dIn = (ref int p) => { }; // error: cannot match `ref` to `in`
DRef dRef = (in int p) => { }; // warning: mismatch between `in` and `ref`
DRR dRR = (ref int p) => { }; // error: cannot match `ref` to `ref readonly`
dRR = (in int p) => { }; // warning: mismatch between `in` and `ref readonly`
dIn = (ref readonly int p) => { }; // warning: mismatch between `ref readonly` and `in`
dRef = (ref readonly int p) => { }; // warning: mismatch between `ref readonly` and `ref`
delegate void DIn(in int p);
delegate void DRef(ref int p);
delegate void DRR(ref readonly int p);
Beachten Sie, dass es keine Änderung des Verhaltens von Funktionszeigerkonvertierungen gibt. Zu Erinnerung: Implizite Funktionszeigerkonvertierungen sind nicht zulässig, wenn es einen Konflikt zwischen Verweistypmodifizierern gibt. Explizite Konvertierungen sind immer ohne Warnungen zulässig.
Signaturabgleich
In einem einzelnen Typ deklarierte Mitglieder können sich nicht ausschließlich in ihrer Signatur durch ref
/out
/in
/ref readonly
unterscheiden.
Für andere Zwecke des Signaturabgleichs (z. B. Ausblenden oder Überschreiben) ist der Austausch gegen einen ref readonly
in
- Modifizierer möglich, dies führt jedoch zu einer Warnung an der Deklarationsstelle [§7.6].
Dies gilt nicht beim Abgleich der partial
-Deklaration mit ihrer Implementierung und der Interceptor-Signatur mit der abgefangenen Signatur.
Beachten Sie, dass es keine Änderungen beim Überschreiben für ref
/in
- und ref readonly
/ref
-Modifier-Paare gibt; sie können nicht ausgetauscht werden, da die Signaturen nicht binär kompatibel sind.
Aus Konsistenzgründen gilt dies auch für andere Signaturabgleichszwecke (z. B. Ausblenden).
Metadatencodierung
Als Erinnerung,
-
ref
-Parameter werden als einfache byref-Typen ausgegeben (T&
in IL), in
Parameter sind wieref
, aber sie werden mitSystem.Runtime.CompilerServices.IsReadOnlyAttribute
annotiert. In C# 7.3 und höher werden sie auch mit[in]
und, wenn virtuell, mitmodreq(System.Runtime.InteropServices.InAttribute)
ausgegeben.
ref readonly
-Parameter werden als [in] T&
ausgegeben und mit dem folgenden Attribut versehen:
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
public sealed class RequiresLocationAttribute : Attribute
{
}
}
Darüber hinaus werden sie, falls sie virtuell sind, mit modreq(System.Runtime.InteropServices.InAttribute)
emittiert, um die binäre Kompatibilität mit in
Parametern sicherzustellen.
Beachten Sie, dass im Gegensatz zu in
-Parametern keine [IsReadOnly]
für ref readonly
-Parameter ausgegeben werden, um zu vermeiden, dass der Umfang der Metadaten größer wird, und dass ältere Compilerversionen ref readonly
-Parameter als ref
-Parameter interpretieren (und daher ist ref
→ ref readonly
keine disruptive Quelländerung, selbst zwischen verschiedenen Compilerversionen).
Das RequiresLocationAttribute
wird anhand des namespace-qualifizierten Namens abgeglichen und vom Compiler synthetisiert, wenn es noch nicht in der Kompilierung enthalten ist.
Das Angeben des Attributs in der Quelle ist ein Fehler, wenn es auf einen Parameter angewendet wird, ähnlich wie ParamArrayAttribute
.
Funktionszeiger
In Funktionszeigern werden in
-Parameter mit modreq(System.Runtime.InteropServices.InAttribute)
verwendet (siehe Vorschlag für Funktionszeiger).
ref readonly
-Parameter werden ohne modreq
ausgegeben, sondern stattdessen mit modopt(System.Runtime.CompilerServices.RequiresLocationAttribute)
.
Ältere Compilerversionen ignorieren das modopt
und interpretieren deshalb ref readonly
-Parameter als ref
-Parameter (was dem Verhalten älterer Compilerversionen bei normalen Methoden mit ref readonly
-Parametern entspricht, wie oben beschrieben). Neue Compilerversionen, die über das modopt
informiert sind, nutzen es hingegen, um ref readonly
-Parameter zu erkennen und während -Konvertierungen und -AufrufenWarnungen auszugeben.
Für die Konsistenz mit älteren Compilerversionen melden neue Compilerversionen mit LangVersion <= 11
Fehler, dass ref readonly
-Parameter nicht unterstützt werden, es sei denn, die entsprechenden Argumente werden mit dem ref
-Modifizierer übergeben.
Beachten Sie, dass es sich bei der Änderung von Modifizierern in Funktionszeigersignaturen um eine disruptive Binäränderung handelt, wenn sie Teil öffentlicher APIs sind; daher handelt es sich um eine disruptive Binäränderung, wenn ref
oder in
zu ref readonly
geändert wird.
Eine disruptive Quelländerung tritt jedoch nur für Caller mit LangVersion <= 11
auf, wenn in
→ ref readonly
geändert wird (wenn der Zeiger mit dem Callsite-Modifizierer in
aufgerufen wird), konsistent mit normalen Methoden.
Disruptive Änderungen
Die ref
/in
Konfliktlockerung bei der Überladungsauflösung führt zu einer disruptiven Verhaltensänderung, wie im nachfolgenden Beispiel illustriert:
class C
{
string M(in int i) => "C";
static void Main()
{
int i = 5;
System.Console.Write(new C().M(ref i));
}
}
static class E
{
public static string M(this C c, ref int i) => "E";
}
In C# 11 wird der Aufruf an E.M
gebunden, daher wird "E"
gedruckt.
In C# 12 darf C.M
gebunden werden (mit einer Warnung), und Erweiterungsbereiche werden nicht durchsucht, da wir einen verwendbaren Kandidaten haben. Daher wird "C"
gedruckt.
Aus demselben Grund liegt auch eine disruptive Quelländerung vor.
Im folgenden Beispiel wird "1"
in C# 11 gedruckt, aber die Kompilierung in schlägt aufgrund eines Mehrdeutigkeitsfehlers fehl.
var i = 5;
System.Console.Write(C.M(null, ref i));
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";
}
Die obigen Beispiele veranschaulichen die Disruptionen für Methodenaufrufe, aber da sie durch Änderungen bei Überladungsauflösungsänderungen verursacht werden, können sie für Methodenkonvertierungen in ähnlicher Weise ausgelöst werden.
Alternativen
Parameter-Deklarierungen
API-Autoren könnten in
-Parameter mit Anmerkungen versehen, die nur lvalues mit einem benutzerdefinierten Attribut akzeptieren, und eine Analyse bereitstellen, um inkorrekte Verwendungen zu kennzeichnen.
Dies würde API-Autoren nicht ermöglichen, Signaturen vorhandener APIs zu ändern, die sich für die Verwendung von ref
-Parametern entschieden haben, um rvalues nicht zuzulassen.
Aufrufer solcher APIs müssen weiterhin zusätzliche Arbeit leisten, um eine ref
zu erhalten, wenn sie nur Zugriff auf eine ref readonly
-Variable haben.
Das Ändern dieser APIs von ref
zu [RequiresLocation] in
wäre eine disruptive Quelländerung (und bei virtuellen Methoden auch eine disruptive Binäränderung).
Anstatt den Modifizierer ref readonly
zuzulassen, konnte der Compiler erkennen, wann ein spezielles Attribut (wie [RequiresLocation]
) auf einen Parameter angewendet wird.
Dies wurde in LDM 2022-04-25erörtert, wobei dies ein Sprachmerkmal ist, kein Analysewerkzeug, daher sollte es auch wie eines aussehen.
Prüfungen von Wertarten
Das Übergeben von lvalues ohne Modifizierer an ref readonly
-Parameter könnte ohne Warnungen zugelassen werden, ähnlich den impliziten byref-Parametern in C++.
Dies wurde in LDM 2022-05-11erörtert, wobei festgestellt wurde, dass der Hauptgrund für ref readonly
-Parameter APIs sind, die Verweise aus diesen Parametern erfassen oder zurückgeben. Daher ist eine Art Markierung von Vorteil.
Die Übergabe eines rvalue an eine ref readonly
könnte ein Fehler und keine Warnung sein.
Das wurde zunächst in LDM 2022-04-25akzeptiert, aber in späteren E-Mail-Diskussionen wurde dies jedoch relativiert, da dabei die Möglichkeit verloren ginge, vorhandene APIs zu ändern, ohne die Benutzer zu beeinträchtigen.
in
könnte der „natürliche“ Callsite-Modifizierer für ref readonly
-Parameter sein, und die Verwendung von ref
könnte zu Warnungen führen.
Dadurch wird ein konsistenter Code-Stil sichergestellt, und an der Callsite wäre offensichtlich, dass der Verweis schreibgeschützt ist (im Gegensatz zu ref
).
Dies wurde in LDM 2022-04-25zuerst akzeptiert.
Warnungen können jedoch ein Reibungspunkt für API-Autoren sein, um von ref
zu ref readonly
zu wechseln.
Außerdem wurde in
als ref readonly
plus Komfortmerkmale neu definiert, weshalb dies in LDM 2022-05-11abgelehnt wurde.
LDM-Überprüfung ausstehend
In C# 12 wurden keine der folgenden Optionen implementiert. Diese bleiben potenzielle Vorschläge.
Parameter-Deklarierungen
Umgekehrte Sortierung von Modifizierern (readonly ref
anstelle von ref readonly
) kann zulässig sein.
Dies wäre inkonsistent mit der Art und Weise, in der sich readonly ref
Rückgaben und Felder verhalten (umgekehrte Sortierung ist nicht zulässig oder hat eine andere Bedeutung) und könnte in Zukunft mit schreibgeschützten Parametern in Konflikt geraten.
Standardwerte könnten für die ref readonly
-Parameter fehlerhaft sein.
Prüfungen von Wertarten
Fehler können anstelle von Warnungen ausgegeben werden, wenn rvalues an ref readonly
-Parameter übergeben oder Callsite-Anmerkungen und Parametermodifizierer nicht übereinstimmen.
Ebenso kann spezielles modreq
anstelle eines Attributs verwendet werden, damit ref readonly
-Parameter sich von in
-Parametern auf Binär-Ebene unterscheiden.
Dies würde stärkere Garantien bieten und wäre daher für neue APIs sinnvoll, würde jedoch die Einführung in bestehende Runtime-APIs verhindern, bei denen keine disruptiven Änderungen zulässig sind.
Wertartenüberprüfungen könnten gelockert werden, um schreibgeschützte Referenzen über ref
in in
/ref readonly
-Parameter zu übergeben.
Das wäre vergleichbar damit, wie Zuweisungen und Rückgaben von Verweisen derzeit funktionieren – sie ermöglichen auch das Übergeben von Verweisen in schreibgeschützter Form über den ref
-Modifizierer im Quellausdruck.
Die ref
befindet sich jedoch in der Regel nahe der Stelle, an der das Ziel als ref readonly
deklariert wird. Daher ist klar, dass wir einen Verweis in schreibgeschützter Form übergeben, im Gegensatz zu Aufrufen, deren Argument- und Parametermodifizierer sich normalerweise weit voneinander entfernt befinden.
Darüber hinaus erlauben sie nur den ref
-Modifizierer, im Gegensatz zu Argumenten, die auch in
zulassen; daher würden in
und ref
gegen Argumente austauschbar werden, oder in
würden praktisch veraltet werden, wenn Benutzer ihren Code konsistent machen wollten (sie würden wahrscheinlich überall ref
verwenden, da dies der einzige Modifizierer ist, der für Zuweisungen und Rückgaben von Referenzen zulässig ist).
Überladungsauflösung
Überladungsauflösung, Überschreibung und Konvertierung könnten die Austauschbarkeit von ref readonly
und in
-Modifizierern unzulässig machen.
Die Änderung der Überladungsauflösung für vorhandene in
-Parameter könnte bedingungslos übernommen werden (ohne Berücksichtigung der LangVersion). Dies wäre jedoch eine disruptive Änderung.
Der Aufruf einer Erweiterungsmethode mit dem Empfänger ref readonly
kann die Warnung „Argument 1 sollte mit dem Schlüsselwort ref
oder in
übergeben werden“ auslösen, ähnlich wie dies bei Nicht-Erweiterungsaufrufen ohne Callsite-Modifizierer vorkommen würde (der Benutzer könnte diese Warnung beheben, indem der Aufruf der Erweiterungsmethode in einen statischen Methodenaufruf umgewandelt wird).
Dieselbe Warnung kann erfolgen, wenn ein benutzerdefinierter Sammlungsinitialisierer oder ein Handler für interpolierte Zeichenfolgen mit dem Parameter ref readonly
verwendet wird, auch wenn der Benutzer keinen Workaround dafür verwenden konnte.
ref readonly
-Überladungen könnten gegenüber Wert-Überladungen bevorzugt werden, wenn kein Callsite-Modifizierer vorhanden ist, oder wenn ein Mehrdeutigkeitsfehler vorliegen könnte.
Methodenkonvertierungen
Wir könnten zulassen, dass der ref
-Parameter der Zielmethode dem in
- und ref readonly
-Parameter des Delegaten entspricht.
Dies würde es API-Autoren ermöglichen, beispielsweise in Delegatensignaturen ref
zu in
zu ändern, ohne ihre Benutzer zu beeinträchtigen, was konsistent mit dem ist, was für normale Methodensignaturen zulässig ist.
Dies würde jedoch auch zu folgendem Verstoß gegen readonly
- Garantien, lediglich mit einer Warnung, führen:
class Program
{
static readonly int f = 123;
static void Main()
{
var d = (in int x) => { };
d = (ref int x) => { x = 42; }; // warning: mismatch between `ref` and `in`
d(f); // changes value of `f` even though it is `readonly`!
System.Console.WriteLine(f); // prints 42
}
}
Konvertierungen von Funktionszeigern könnten bei ref readonly
/ref
/in
-Konflikten warnen, aber um dies von der LangVersion abhängig zu machen, wäre eine erhebliche Implementierungsinvestition erforderlich, da Typkonvertierungen derzeit keinen Zugriff auf den Kompilierungsprozess erfordern.
Auch wenn ein Konflikt derzeit als Fehler gilt, ist es für Benutzer einfach, eine Umwandlung hinzuzufügen, um den Konflikt bei Bedarf zuzulassen.
Codierung von Metadaten
Das Angeben von RequiresLocationAttribute
in der Quelle könnte zulässig sein, ähnlich wie die Attribute In
und Out
.
Alternativ kann es sich um einen Fehler handeln, wenn er in anderen Kontexten als nur Parameter angewendet wird, ähnlich wie das IsReadOnly
-Attribut, um zusätzlichen Gestaltungsspielraum zu bewahren.
Funktionszeiger-ref readonly
-Parameter können mit unterschiedlichen modopt
/modreq
Kombinationen ausgegeben werden (beachten Sie, dass „disruptive Quelländerung“ in dieser Tabelle für Aufrufer mit LangVersion <= 11
bedeutet):
Zusatztasten | Kann über Kompilierungen hinweg erkannt werden | Alte Compiler sehen sie als | ref → ref readonly |
in → ref readonly |
---|---|---|---|---|
modreq(In) modopt(RequiresLocation) |
Ja | in |
disruptive Binär-, Quelländerung | disruptive Binäränderung |
modreq(In) |
Nein | in |
disruptive Binär-, Quelländerung | Okay |
modreq(RequiresLocation) |
Ja | nicht unterstützt | disruptive Binär-, Quelländerung | disruptive Binär-, Quelländerung |
modopt(RequiresLocation) |
Ja | ref |
disruptive Binäränderung | disruptive Binär-, Quelländerung |
Wir könnten sowohl die Attribute [RequiresLocation]
als auch [IsReadOnly]
für die ref readonly
-Parameter ausgeben.
Dann wäre in
→ ref readonly
selbst für ältere Compilerversionen keine disruptive Quelländerung aber ref
→ ref readonly
wäre eine disruptive Quelländerung für ältere Compiler (da diese ref readonly
als in
interpretieren würden, wodurch ref
-Modifizierer nicht zulässig wären) und neuere Compilerversionen mit LangVersion <= 11
(aus Konsistenzgründen).
Wir könnten das Verhalten für LangVersion <= 11
von dem Verhalten für ältere Compilerversionen unterscheiden.
Beispielsweise kann es sich um einen Fehler handeln, wenn ein ref readonly
-Parameter aufgerufen wird (auch wenn der ref
-Modifizierer an der Callsite verwendet wird), oder dies kann immer ohne Fehler zulässig sein.
Disruptive Änderungen
Dieser Vorschlag schlägt vor, eine disruptive Verhaltensänderung zu akzeptieren, da dies selten auftreten sollte, durch die LangVersion eingeschränkt wird, und Benutzer sie umgehen können, indem sie die Erweiterungsmethode explizit aufrufen. Stattdessen könnten wir dies beheben, indem wir
- den
ref
/in
-Konflikt nicht zulassen (dies würde lediglich die Migration zuin
für alte APIs verhindern, dieref
verwendet haben, dain
noch nicht verfügbar war), - Ändern der Regeln für die Überladungsauflösung, um weiterhin nach einer besseren Übereinstimmung zu suchen (bestimmt durch die unten angegebenen Verbesserungsregeln), wenn in diesem Vorschlag ein solcher Konflikt eingeführt wurde,
- oder alternativ nur bei
ref
vs.in
-Konflikt fortfahren, nicht für andere (ref readonly
vs.ref
/in
/nach-Wert).
- oder alternativ nur bei
Verbesserungsregeln
Das folgende Beispiel führt derzeit zu drei Mehrdeutigkeitsfehlern für die drei Aufrufe von M
.
Wir könnten neue Verbesserungsregeln hinzufügen, um die Mehrdeutigkeiten aufzulösen.
Dies würde auch die zuvor beschriebene disruptive Quelländerung beheben.
Eine Möglichkeit wäre, das Beispiel 221
drucken zu lassen, wobei der ref readonly
-Parameter mit dem in
-Argument abgeglichen wird, da es zu einer Warnung führen würde, es ohne Modifizierer aufzurufen, während dies für den in
-Parameter zulässig ist.
interface I1 { }
interface I2 { }
class C
{
static string M(I1 o, in int i) => "1";
static string M(I2 o, ref readonly int i) => "2";
static void Main()
{
int i = 5;
System.Console.Write(M(null, ref i));
System.Console.Write(M(null, in i));
System.Console.Write(M(null, i));
}
}
Neue Verbesserungsregeln könnten den Parameter, dessen Argument mit einem anderen Argumentmodifizierer übergeben worden sein könnte, als schlechter markieren, um ihn besser zu machen.
Mit anderen Worten: Der Benutzer sollte immer in der Lage sein, einen schlechteren Parameter in einen besseren Parameter umzuwandeln, indem er seinen entsprechenden Argumentmodifizierer ändert.
Wenn beispielsweise ein Argument von in
übergeben wird, wird ein ref readonly
-Parameter gegenüber einem in
-Parameter bevorzugt, da der Benutzer das Argument nach Wert übergeben kann, um den in
-Parameter auszuwählen.
Diese Regel ist nur eine Erweiterung der Nach-Wert-/in
Präferenzregel, die derzeit gilt (es handelt sich um die letzte Überladungsauflösungsregel und die gesamte Überladung ist besser, wenn ein Parameter besser und keiner schlechter als der entsprechende Parameter einer anderen Überladung ist).
Argument | besserer Parameter | schlechterer Parameter |
---|---|---|
ref /in |
ref readonly |
in |
ref |
ref |
ref readonly /in |
Nach Wert | Nach Wert/in |
ref readonly |
in |
in |
ref |
Wir sollten Methodenkonvertierungen ähnlich behandeln.
Das folgende Beispiel führt derzeit zu zwei Mehrdeutigkeitsfehlern für die beiden Delegatzuweisungen.
Neue Verbesserungsregeln könnten einen Methodenparameter bevorzugen, dessen Refness-Modifizierer dem entsprechenden Refness-Modifizierer des Zieldelegatparameters entspricht, gegenüber einem solchen, bei dem sie nicht übereinstimmen.
Daher würde das folgende Beispiel 12
drucken.
class C
{
void M(I1 o, ref readonly int x) => System.Console.Write("1");
void M(I2 o, ref int x) => System.Console.Write("2");
void Run()
{
D1 m1 = this.M;
D2 m2 = this.M; // currently ambiguous
var i = 5;
m1(null, in i);
m2(null, ref i);
}
static void Main() => new C().Run();
}
interface I1 { }
interface I2 { }
class X : I1, I2 { }
delegate void D1(X s, ref readonly int x);
delegate void D2(X s, ref int x);
Design Meetings
- LDM 2022-04-25: Funktion akzeptiert
- LDM 2022-05-09: Die Diskussion wurde in drei Teile unterteilt
- LDM 2022-05-11: zulässig
ref
und keine Callsite-Anmerkung fürref readonly
-Parameter
C# feature specifications