ref readonly
parametrar
Obs
Den här artikeln är en funktionsspecifikation. Specifikationen fungerar som designdokument för funktionen. Den innehåller föreslagna specifikationsändringar, tillsammans med information som behövs under utformningen och utvecklingen av funktionen. Dessa artiklar publiceras tills de föreslagna specifikationsändringarna har slutförts och införlivats i den aktuella ECMA-specifikationen.
Det kan finnas vissa skillnader mellan funktionsspecifikationen och den slutförda implementeringen. Dessa skillnader noteras i de relevanta anteckningarna från LDM (Language Design Meeting) .
Du kan läsa mer om processen för att införa funktionsspecifikationer i C#-språkstandarden i artikeln om specifikationerna.
Champion-utgåva: https://github.com/dotnet/csharplang/issues/6010
Sammanfattning
Tillåt parameterdeklarationsplatsmodifikator ref readonly
och ändra anropsregler enligt följande:
Anropsplatsanteckning |
ref parameter |
ref readonly parameter |
in parameter |
out parameter |
---|---|---|---|---|
ref |
Tillåten | Tillåten | Varning | Fel |
in |
Fel | Tillåten | Tillåten | Fel |
out |
Fel | Fel | Fel | Tillåten |
Ingen anteckning | Fel | Varning | Tillåten | Fel |
(Observera att det finns en ändring av befintliga regler: in
parameter med ref
anropsobjektanteckning ger en varning i stället för ett fel.)
Ändra argumentvärderegler på följande sätt:
Värdetyp |
ref parameter |
ref readonly -parametrar |
in -parametern |
out parameter |
---|---|---|---|---|
rvalue | Fel | Varning | Tillåten | Fel |
Lvalue | Tillåten | Tillåten | Tillåten | Tillåten |
Där lvalue betyder en variabel (dvs. ett värde med en plats, inte behöver skrivas/tilldelas) och rvalue innebär någon typ av värde.
Motivation
C# 7.2 introducerade in
parametrar som ett sätt att skicka skrivskyddade referenser.
in
parametrar tillåter både lvalues och rvalues och kan användas utan någon anteckning på anropsplatsen.
API:er som samlar in eller returnerar referenser från sina parametrar vill dock inte tillåta rvalues och även framtvinga en viss indikation på anropsplatsen om att en referens registreras.
ref readonly
-parametrar är perfekta i sådana fall eftersom de varnar när de används med r-värden eller utan någon annotering på anropsplatsen.
Dessutom finns det API:er som bara behöver skrivskyddade referenser men som använder
-
ref
parametrar eftersom de introducerades innanin
blev tillgängliga och att ändra tillin
skulle vara en käll- och binär icke-bakåtkompatibel ändring, t.ex.QueryInterface
, eller -
in
parametrar för att acceptera endast-läs referenser även om det inte är särskilt logiskt att överföra rvalues till dem, t.ex.ReadOnlySpan<T>..ctor(in T value)
, eller -
ref
parametrar för att inte tillåta r-värden även om de inte muterar den skickade referensen, t.ex.Unsafe.IsNullRef
.
Dessa API:er kan migreras till ref readonly
parametrar utan att det påverkar användarna.
Mer information om binär kompatibilitet finns i den föreslagna metadatakodning.
Mer specifikt, ändring
-
ref
→ref readonly
skulle bara vara en brytande binär förändring för virtuella metoder, -
ref
→in
skulle också vara en binär ändring som bryter bakåtkompatibiliteten för virtuella metoder, men inte en ändring som bryter källkodens bakåtkompatibilitet (eftersom reglerna ändras för att endast varna förref
argument som skickas tillin
parametrar), -
in
→ref readonly
skulle inte bryta kompatibiliteten (men ingen anropsplatsannotation eller rvalue skulle resultera i en varning),- Observera att detta skulle vara en källbrytande ändring för användare som använder äldre kompilatorversioner (eftersom de tolkar
ref readonly
parametrar somref
parametrar, tillåter intein
eller ingen anteckning på anropsplatsen) och nya kompilatorversioner medLangVersion <= 11
(för konsekvens med äldre kompilatorversioner genereras ett fel somref readonly
parametrar inte stöds om inte motsvarande argument skickas medref
modifieraren).
- Observera att detta skulle vara en källbrytande ändring för användare som använder äldre kompilatorversioner (eftersom de tolkar
I motsatt riktning, ändra
-
ref readonly
→ref
skulle potentiellt vara en källkodsbrytande ändring (såvida inte endastref
-anropsobjektanteckningen användes och bara skrivskyddade referenser användes som argument) och en binärbrytande ändring för virtuella metoder. -
ref readonly
→in
skulle inte vara en brytande förändring (menref
anropsplatsanteckning skulle resultera i en varning).
Observera att reglerna som beskrivs ovan gäller för metodsignaturer, men inte för att delegera signaturer.
Att till exempel ändra ref
till in
i en ombudssignatur kan vara en källbrytande ändring (om en användare tilldelar en metod med ref
parametern till den delegerade typen skulle det bli ett fel efter API-ändringen).
Detaljerad design
I allmänhet är reglerna för ref readonly
parametrar desamma som de som anges för in
parametrar i deras förslag, förutom när det uttryckligen har ändrats i det här förslaget.
Parameterdeklarationer
Det krävs inga ändringar i grammatiken.
Modifieraren ref readonly
tillåts för parametrar.
Förutom normala metoder tillåts ref readonly
för indexeringsparametrar (som in
men till skillnad från ref
), men tillåts inte för operatorparametrar (som ref
men till skillnad från in
).
Standardparametervärden tillåts för ref readonly
parametrar med en varning eftersom de motsvarar att skicka rvalues.
Detta gör att API-författare kan ändra in
parametrar med standardvärden till ref readonly
parametrar utan att införa en kompatibilitetsbrytande ändring.
Kontroller av värdetyp
Observera att även om ref
argumentmodifierare tillåts för ref readonly
parametrar, ändras inget w.r.t. värdetypkontroller, d.v.s.
-
ref
kan endast användas med tilldelningsbara värden. - för att skicka skrivskyddade referenser måste man i stället använda argumentmodifieraren
in
. - för att klara rvalues måste man inte använda någon modifierare (vilket resulterar i en varning för
ref readonly
parametrar enligt beskrivningen i sammanfattningen av detta förslag).
Överbelastningsupplösning
Med överlagringsmatchning kan ref
/ref readonly
/in
/no callsite-anteckningar och parametermodifierare blandas enligt tabellen i sammanfattningen av det här förslaget, d.v.s. alla tillåtna och varning fall kommer att betraktas som möjliga kandidater vid överbelastningsmatchning.
Mer specifikt finns det en ändring i befintligt beteende där metoder med in
-parametern matchar anrop med motsvarande argument markerat som ref
– den här ändringen kommer att styras av LangVersion.
Dock ignoreras varningen för att skicka ett argument utan anropsplatsmodifierare till en ref readonly
-parameter om parametern är
- mottagaren i ett tilläggsmetodanrop,
- används implicit som del av anpassad insamlingsinitierare eller interpolerad stränghanterare.
Överlagringar efter värde föredras framför ref readonly
överlagringar om det inte finns någon argumentmodifierare (in
parametrar har samma beteende).
Metodkonverteringar
För anonym funktion [§10.7] och metodgruppen [§10.8] anses dessa modifierare vara kompatibla (men alla tillåtna konverteringar mellan olika modifierare resulterar i en varning):
-
ref readonly
parametern för målmetoden tillåts matchain
ellerref
parametern för ombudet, -
in
-parametern för målmetoden tillåts matcharef readonly
eller, beroende på LangVersion,ref
-parametern för delegeringen. - Obs!
ref
parametern för målmetoden inte tillåts matchain
ellerref readonly
parameter för ombudet.
Till exempel:
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);
Observera att funktionspekarkonverteringarnas beteende inte ändras. Som en påminnelse tillåts inte implicita funktionpekaromvandlingar om det finns en diskrepans mellan referenstypmodifierare, och explicita kastningar är alltid tillåtna utan några varningar.
Signaturmatchning
Medlemmar som deklareras i en enda typ kan inte skilja sig åt i signaturen enbart av ref
/out
/in
/ref readonly
.
För andra syften med signaturmatchning (t.ex. döljande eller åsidosättande) kan ref readonly
ersättas med in
modifierare, men det resulterar i en varning på deklarationsplatsen [§7.6].
Detta gäller inte vid matchning av partial
-deklaration med dess implementering och vid matchning av interceptor-signatur med avlyssnad signatur.
Observera att det inte finns någon ändring i åsidosättning av ref
/in
och ref readonly
/ref
modifierarpar. De kan inte bytas ut, eftersom signaturerna inte är binärkompatibla.
För att vara konsekvent gäller samma sak för andra signaturmatchningsändamål (t.ex. gömning).
Metadatakodning
Som en påminnelse
-
ref
parametrar genereras som vanliga byref-typer (T&
i IL), -
in
parametrar är somref
plus att de kommenteras medSystem.Runtime.CompilerServices.IsReadOnlyAttribute
. I C# 7.3 och senare genereras de också med[in]
ochmodreq(System.Runtime.InteropServices.InAttribute)
om de är virtuella.
ref readonly
parametrar kommer att utges som [in] T&
, plus att de noteras med följande attribut:
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
public sealed class RequiresLocationAttribute : Attribute
{
}
}
Om de är virtuella genereras de dessutom med modreq(System.Runtime.InteropServices.InAttribute)
för att säkerställa binär kompatibilitet med in
parametrar.
Observera att till skillnad från in
parametrar genereras inga [IsReadOnly]
för ref readonly
parametrar för att undvika att öka metadatastorleken och även för att göra så att äldre kompilatorversioner tolkar ref readonly
parametrar som ref
parametrar (och därför kommer ref
→ ref readonly
inte att vara en källbrytande ändring även mellan olika kompilatorversioner).
RequiresLocationAttribute
matchas med namnområdeskvalificerat namn och syntetiseras av kompilatorn om den inte redan ingår i kompilering.
Att ange attributet i källan är ett fel om det tillämpas på en parameter, på samma sätt som ParamArrayAttribute
.
Funktionspekare
I funktionspekare genereras in
parametrar med modreq(System.Runtime.InteropServices.InAttribute)
(se förslag på funktionspekare).
ref readonly
parametrar kommer att utsändas utan modreq
, men istället med modopt(System.Runtime.CompilerServices.RequiresLocationAttribute)
.
Äldre kompilatorversioner ignorerar modopt
och tolkar därför ref readonly
parametrar som ref
parametrar (överensstämmer med äldre kompilatorbeteende för normala metoder med ref readonly
parametrar enligt beskrivningen ovan) och nya kompilatorversioner som är medvetna om modopt
använder den för att identifiera ref readonly
parametrar för att generera varningar under konverteringar och anrop.
För konsekvens med äldre kompilatorversioner rapporterar nya kompilatorversioner med LangVersion <= 11
fel för att ref readonly
-parametrar inte stöds om inte motsvarande argument skickas med ref
-modifieraren.
Observera att det är en binär paus att ändra modifierare i funktionspekarsignaturer om de är en del av offentliga API:er, vilket innebär att det blir en binär paus när du ändrar ref
eller in
till ref readonly
.
En källbrytning sker dock bara för anropare med LangVersion <= 11
vid ändring av in
till ref readonly
(om pekaren anropas med in
anropsmodifierare), i enlighet med normala metoder.
Icke-bakåtkompatibla ändringar
Den ref
/in
matchningsfelsavslappningen i överbelastningsmatchningen introducerar en beteendebrytande ändring som visas i följande exempel:
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";
}
I C# 11 binder anropet till E.M
, och därför skrivs "E"
ut.
I C# 12 tillåts C.M
att binda (med en varning) och inga tilläggsomfång genomsöks eftersom vi har en tillämplig kandidat, och därför skrivs "C"
ut.
Det finns också en källbrytande ändring på grund av samma orsak.
Exemplet nedan skriver ut "1"
i C# 11, men kan inte kompileras med ett tvetydighetsfel i C# 12:
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";
}
Exemplen ovan visar avbrott för metodanrop, men eftersom de orsakas av ändringar i överbelastningsmatchningen kan de utlösas på samma sätt för metodkonverteringar.
Alternativ
parameterdeklarationer
API-författare kan kommentera in
parametrar som är utformade för att endast acceptera lvalues med ett anpassat attribut och tillhandahålla en analysator för att flagga felaktiga användningar.
Detta skulle inte tillåta API-författare att ändra signaturer för befintliga API:er som valde att använda ref
parametrar för att neka rvalues.
Anropare av sådana API:er skulle fortfarande behöva utföra extra arbete för att få en ref
om de bara har åtkomst till en ref readonly
variabel.
Att ändra dessa API:er från ref
till [RequiresLocation] in
skulle vara en källbrytande ändring (och i fallet med virtuella metoder, också en binär brytande ändring).
I stället för att tillåta modifieraren ref readonly
kan kompilatorn identifiera när ett särskilt attribut (som [RequiresLocation]
) tillämpas på en parameter.
Detta diskuterades i LDM 2022-04-25, och beslutade att detta är en språkfunktion, inte en analysator, så det bör se ut som en.
Kontroll av värdeslag
Att skicka lvalues utan några modifierare till ref readonly
parametrar kan tillåtas utan några varningar, på samma sätt som C++:s implicita byref-parametrar.
Detta diskuterades i LDM 2022-05-11, och noterade att den primära motivationen för ref readonly
parametrar är API:er som samlar in eller returnerar referenser från dessa parametrar, så markör av något slag är bra.
Att skicka rvalue till en ref readonly
kan vara ett fel, inte en varning.
Det accepterades ursprungligen i LDM 2022-04-25, men senare e-postdiskussioner lättade på detta eftersom vi skulle förlora möjligheten att ändra befintliga API:er utan att bryta användarna.
in
kan vara en "naturlig" anropsmodifierare för ref readonly
parametrar och användning av ref
kan resultera i varningar.
Detta skulle säkerställa ett konsekvent kodformat och göra det uppenbart på anropsplatsen att referensen är skrivskyddad (till skillnad från ref
).
Det accepterades ursprungligen i LDM 2022-04-25.
Varningar kan dock vara en friktionspunkt för API-författare att gå från ref
till ref readonly
.
Dessutom har in
omdefinierats som ref readonly
+ bekvämlighetsfunktioner, därför avvisades detta i LDM 2022-05-11.
Väntande LDM-granskning
Inget av följande alternativ implementerades i C# 12. De är fortfarande potentiella förslag.
parameterdeklarationer
Omvänd ordning av modifierare (readonly ref
i stället för ref readonly
) kan tillåtas.
Detta skulle vara oförenligt med hur readonly ref
returnerar och fält beter sig (omvänd ordning tillåts inte eller innebär något annat) och kan kollidera med skrivskyddade parametrar om det implementeras i framtiden.
Standardparametervärden kan vara ett fel för ref readonly
parametrar.
Typ av värde kontroller
Fel kan utlösas istället för varningar när "rvalues" skickas till ref readonly
-parametrar eller vid inkorrekt matchning av anropsanteckningar och parametermodifierare.
På samma sätt kan särskilda modreq
användas i stället för ett attribut för att säkerställa att ref readonly
parametrar skiljer sig från in
parametrar på binär nivå.
Detta skulle ge starkare garantier, så det skulle vara bra för nya API:er, men förhindra implementering i befintliga körnings-API:er som inte kan införa icke-bakåtkompatibla ändringar.
Kontroller av värdeslag kan bli mindre strikta för att tillåta att skrivskyddade referenser skickas via ref
till in
/ref readonly
parametrar.
Det skulle likna hur referenstilldelningar och referensreturer fungerar i dag – de tillåter även att referenser skickas skrivskyddat via ref
-modifieraren i källuttrycket.
Men ref
där finns vanligtvis nära platsen där målet deklareras som ref readonly
, så det är tydligt att vi skickar en referens som readonly, till skillnad från anrop där argument- och parametermodifierare vanligtvis befinner sig långt ifrån varandra.
Dessutom tillåter de endastref
modifierare till skillnad från argument som också tillåter in
, vilket innebär att in
och ref
skulle bli utbytbara för argument, eller in
skulle bli praktiskt taget föråldrad om användarna ville göra sin kod konsekvent (de skulle förmodligen använda ref
överallt eftersom det är den enda modifieraren som tillåts för referenstilldelningar och ref-returer).
överbelastningsupplösning
Överbelastningslösning, åsidosättning och konvertering kan förhindra utbytbarhet av ref readonly
och in
modifikatorer.
Ändringen av överbelastningslösningen för befintliga in
-parametrar kan göras utan villkor (utan hänsyn till LangVersion), men det skulle innebära en brytande förändring.
Om du anropar en tilläggsmetod med ref readonly
mottagare kan det leda till varning om att "Argument 1 ska skickas med ref
eller in
nyckelord" som skulle inträffa för icke-tilläggsanrop utan anropsobjektmodifierare (användaren kan åtgärda en sådan varning genom att omvandla tilläggsmetodens anrop till anrop av statiska metoder).
Samma varning kan rapporteras när du använder anpassad insamlingsinitierare eller interpolerad stränghanterare med ref readonly
parameter, även om användaren inte kunde kringgå den.
ref readonly
överlagringar kan föredras framför överlagringar efter värde när det inte finns någon anropswebbplatsmodifierare eller om det kan uppstå ett tvetydighetsfel.
Metodkonverteringar
Vi kan tillåta att ref
parametern för målmetoden matchar in
och ref readonly
parametern för ombudet.
Detta skulle göra det möjligt för API-författare att ändra till exempel ref
till in
i delegatsignaturer utan att bryta sina användare (konsekvent med vad som är tillåtet för normala metodsignaturer).
Men det skulle också leda till följande överträdelse av readonly
-garantier, endast med en varning:
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
}
}
Funktionspekarkonverteringar kan varna för ref readonly
/ref
/in
skiljaktigheter, men om vi vill begränsa det i LangVersion, skulle en betydande investering i implementering krävas eftersom typkonverteringar idag inte behöver tillgång till kompilering.
Även om matchningsfel för närvarande är ett fel är det dessutom enkelt för användarna att lägga till en cast för att tillåta matchningsfelet om de vill.
metadatakodning
Det kan vara tillåtet att ange RequiresLocationAttribute
i källan, på samma sätt som In
och Out
attribut.
Alternativt kan det vara ett fel när det används i andra kontexter än bara parametrar, på samma sätt som IsReadOnly
attribut. för att bevara ytterligare designutrymme.
Funktionspekarens ref readonly
parametrar kan genereras med olika modopt
/modreq
kombinationer (observera att "source break" i den här tabellen avser anropare med LangVersion <= 11
):
Modifierare | Kan identifieras i olika kompileringar | Gamla kompilatorer ser dem som |
ref → ref readonly |
in → ref readonly |
---|---|---|---|---|
modreq(In) modopt(RequiresLocation) |
Ja | in |
binär, källbrytning | binärt avbrott |
modreq(In) |
Nej | in |
binär, källbrytning | Okej |
modreq(RequiresLocation) |
Ja | Ej stöds | binär, källbrytning | binär, källbrytning |
modopt(RequiresLocation) |
Ja | ref |
binärt avbrott | binär, källbrytning |
Vi kan generera både [RequiresLocation]
- och [IsReadOnly]
-attribut för ref readonly
parametrar.
Då skulle in
→ ref readonly
inte vara en bakåtkompatibilitetsbrytande ändring även för äldre kompilatorversioner, men ref
→ ref readonly
skulle bli en källkodsinkompatibel ändring för äldre kompilatorversioner (eftersom de skulle tolka ref readonly
som in
och inte tillåta ref
-modifierare) samt för nya kompilatorversioner med LangVersion <= 11
(för att säkerställa konsekvens).
Vi kan göra beteendet för LangVersion <= 11
annorlunda än beteendet för äldre kompilatorversioner.
Det kan till exempel vara ett fel när en ref readonly
parameter anropas (även när du använder ref
-modifieraren på anropsplatsen), eller så kan den alltid tillåtas utan fel.
Oförenliga ändringar
Det här förslaget föreslår att acceptera en ändring som bryter mot befintligt beteende eftersom det bör vara sällsynt att stöta på, är gated av LangVersion och användare kan kringgå det genom att anropa tilläggsmetoden direkt. I stället kan vi mildra det genom att
- att inte tillåta
ref
/in
matchningsfel (det skulle bara förhindra migrering tillin
för gamla API:er som använderef
eftersomin
inte var tillgängligt ännu), - Ändra reglerna för överbelastningsupplösning för att fortsätta leta efter en bättre matchning (bestäms av bättrehetsregler som anges nedan) när det finns en ref-typmissanpassning som införts i det här förslaget.
- eller så kan du alternativt fortsätta endast för
ref
motin
mismatch, inte de andra mismatcharna (ref readonly
motref
/in
/by-value).
- eller så kan du alternativt fortsätta endast för
Förbättring styr
Följande exempel resulterar för närvarande i tre tvetydighetsfel för de tre anropen av M
.
Vi skulle kunna lägga till nya bättre regler för att lösa tvetydigheterna.
Detta skulle också lösa den källbrytande ändring som beskrevs tidigare.
Ett sätt är att göra ett exempelutskrift 221
(där ref readonly
-parametern matchas med ett in
-argument eftersom det skulle vara en varning att anropa det utan modifierare, å andra sidan är det tillåtet för in
-parametern).
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));
}
}
Nya bättre regler kan markera som värre parametern vars argument kunde ha skickats med en annan argumentmodifierare för att göra det bättre.
Med andra ord bör användaren alltid kunna omvandla en sämre parameter till en bättre parameter genom att ändra motsvarande argumentmodifierare.
När ett argument till exempel skickas av in
prioriteras en ref readonly
parameter framför en in
parameter eftersom användaren kan skicka argumentets värde för att välja parametern in
.
Den här regeln är bara en utvidgning av by-value/in
preferensregeln som gäller idag (det är den sista regeln i överbelastningsupplösningen och hela överbelastningen är bättre om någon av dess parametrar är bättre och ingen är sämre än motsvarande parameter i en annan överbelastning).
argument | bättre parameter | sämre parameter |
---|---|---|
ref /in |
ref readonly |
in |
ref |
ref |
ref readonly /in |
efter värde | efter värde/in |
ref readonly |
in |
in |
ref |
Vi bör hantera metodkonverteringar på liknande sätt.
Följande exempel resulterar för närvarande i två tvetydighetsfel för de två delegerade tilldelningarna.
Nya bättre regler skulle kunna föredra en metodparameter vars refnessmodifierare matchar motsvarande referensmodifierare för måldelegatparametern framför en som har ett matchningsfel.
Därför skulle följande exempel skriva ut 12
.
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);
Designa möten
- LDM 2022-04-25: funktionen accepteras
- LDM 2022-05-09: diskussion uppdelad i tre delar
-
LDM 2022-05-11: tillåts
ref
och ingen anropsplatsanteckning förref readonly
parametrarna
C# feature specifications