"op patroon gebaseerd gebruik" en "declaraties gebruiken"
Notitie
Dit artikel is een functiespecificatie. De specificatie fungeert als het ontwerpdocument voor de functie. Het bevat voorgestelde specificatiewijzigingen, samen met informatie die nodig is tijdens het ontwerp en de ontwikkeling van de functie. Deze artikelen worden gepubliceerd totdat de voorgestelde specificaties zijn voltooid en opgenomen in de huidige ECMA-specificatie.
Er kunnen enkele verschillen zijn tussen de functiespecificatie en de voltooide implementatie. Deze verschillen worden vastgelegd in de relevante LDM-notities (Language Design Meeting).
Meer informatie over het proces voor het aannemen van functiespeclets in de C#-taalstandaard vindt u in het artikel over de specificaties.
Samenvatting
De taal voegt twee nieuwe mogelijkheden toe rond de using
-instructie om resourcebeheer eenvoudiger te maken: using
moet een wegwerppatroon naast IDisposable
herkennen en een using
declaratie toevoegen aan de taal.
Motivatie
De using
-instructie is vandaag een effectief hulpmiddel voor resourcebeheer, maar het vereist nogal wat ceremonieel gedoe. Methoden die een aantal resources hebben die moeten worden beheerd, kunnen syntactisch vastlopen met een reeks using
instructies. Deze syntaxisbelasting is voldoende dat de meeste richtlijnen voor coderingsstijlen expliciet een uitzondering hebben rond accolades voor dit scenario.
De declaratie using
verwijdert hier veel van de ceremonie en stelt C# op één lijn met andere talen die blokken voor resourcebeheer bevatten. Daarnaast kunnen ontwikkelaars met het patroongebaseerde using
de set typen uitbreiden die hier kunnen deelnemen. In veel gevallen kan de noodzaak om wrapper-typen te creëren, die alleen bestaan om het gebruik van waarden in een using
-instructie mogelijk te maken, worden weggenomen.
Samen kunnen ontwikkelaars met deze functies de scenario's vereenvoudigen en uitbreiden waarin using
kunnen worden toegepast.
Gedetailleerd ontwerp
gebruik van declaratie
Met de taal kan using
worden toegevoegd aan een declaratie van lokale variabelen. Een dergelijke declaratie heeft hetzelfde effect als het declareren van de variabele in een using
instructie op dezelfde locatie.
if (...)
{
using FileStream f = new FileStream(@"C:\users\jaredpar\using.md");
// statements
}
// Equivalent to
if (...)
{
using (FileStream f = new FileStream(@"C:\users\jaredpar\using.md"))
{
// statements
}
}
De levensduur van een using
lokaal wordt verlengd tot aan het einde van de scope waarin het gedeclareerd is. De using
lokale variabelen worden vervolgens verwijderd in de omgekeerde volgorde waarin ze worden gedeclareerd.
{
using var f1 = new FileStream("...");
using var f2 = new FileStream("...");
using var f3 = new FileStream("...");
...
// Dispose f3
// Dispose f2
// Dispose f1
}
Er zijn geen beperkingen rond goto
of een andere controlestroomconstructie ten aanzien van een using
-declaratie. In plaats daarvan fungeert de code net als voor de equivalente using
-instructie:
{
using var f1 = new FileStream("...");
target:
using var f2 = new FileStream("...");
if (someCondition)
{
// Causes f2 to be disposed but has no effect on f1
goto target;
}
}
Een variabele gedeclareerd in een using
lokale declaratie is impliciet alleen-lezen. Dit komt overeen met het gedrag van de lokale bevolking die in een using
verklaring is gedeclareerd.
De taal grammatica voor using
declaraties is het volgende:
local-using-declaration:
'using' type using-declarators
using-declarators:
using-declarator
using-declarators , using-declarator
using-declarator:
identifier = expression
Beperkingen rond using
verklaring:
- Kan niet direct in een
case
label worden weergegeven, maar moet zich in plaats daarvan binnen een blok binnen hetcase
label bevinden. - Wordt mogelijk niet weergegeven als onderdeel van een declaratie van een
out
variabele. - Moet een initialisator hebben voor elke declarator.
- Het lokale type moet impliciet worden omgezet in
IDisposable
of voldoen aan hetusing
patroon.
patroongebaseerd gebruik makend van
De taal voegt het concept van een wegwerppatroon toe voor ref struct
typen: dat is een ref struct
die een toegankelijke Dispose
instantiemethode heeft. Typen die passen bij het vervangbare patroon kunnen deelnemen aan een using
instructie of verklaring zonder dat het nodig is om IDisposable
te implementeren.
ref struct Resource
{
public void Dispose() { ... }
}
using (var r = new Resource())
{
// statements
}
Hierdoor kunnen ontwikkelaars gebruikmaken van using
voor ref struct
typen. Deze typen kunnen geen interfaces implementeren in C# 8 en kunnen daarom niet deelnemen aan using
instructies.
Dezelfde beperkingen van een traditionele using
-instructie zijn hier ook van toepassing: lokale variabelen die zijn gedeclareerd in de using
zijn alleen-lezen, een null
-waarde zal geen uitzondering veroorzaken, enzovoort... De codegeneratie is alleen anders omdat er geen casting naar IDisposable
plaatsvindt voordat de Dispose-functie wordt aangeroepen.
{
Resource r = new Resource();
try {
// statements
}
finally {
if (r != null) r.Dispose();
}
}
Als u wilt dat het in het wegwerppatroon past, moet de methode Dispose
een toegankelijk instantie-lid zijn, geen parameters hebben en een void
retourtype. Het kan geen extensiemethode zijn.
Overwegingen
Geen van deze overwegingen is geïmplementeerd in C# 8
caselabels zonder blokken
Een using declaration
is direct binnen een case
-label illegaal vanwege complicaties rond de werkelijke levensduur ervan. Een mogelijke oplossing is het simpelweg dezelfde levensduur te geven als een out var
op dezelfde locatie. De extra complexiteit van de implementatie van de functie en de eenvoud van de oplossing (voeg gewoon een blok toe aan het case
-label) rechtvaardigde niet om deze route te nemen.
Toekomstige uitbreidingen
vaste lokale bevolking
Een fixed
instructie heeft alle eigenschappen van using
instructies die de mogelijkheid voor using
lokale variabelen motiveerden. Er moet overwogen worden om deze functie ook uit te breiden naar fixed
lokalen. De regels voor levensduur en volgorde moeten even goed van toepassing zijn voor using
en fixed
hier.
C# feature specifications