Delen via


"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 gotoof 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 het case 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 het using 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 IDisposablete 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.