Sdílet prostřednictvím


"použití na základě vzoru" a "using deklarací"

Poznámka

Tento článek je specifikace funkce. Specifikace slouží jako návrhový dokument pro funkci. Zahrnuje navrhované změny specifikace spolu s informacemi potřebnými při návrhu a vývoji funkce. Tyto články se publikují, dokud nebudou navrhované změny specifikace finalizovány a začleněny do aktuální specifikace ECMA.

Mezi specifikací funkce a dokončenou implementací může docházet k nějakým nesrovnalostem. Tyto rozdíly jsou zachyceny v poznámkách schůzky návrhu jazyka (LDM) .

Další informace o procesu přijetí specifikací funkcí do jazyka C# najdete v článku o specifikacích .

Problém šampiona: https://github.com/dotnet/csharplang/issues/114

Shrnutí

Tento jazyk přidá kolem příkazu using dvě nové funkce, které zjednoduší správu prostředků: using by kromě IDisposable měl rozpoznat jednorázový vzor a přidat do jazyka deklaraci using.

Motivace

Prohlášení using je dnes efektivním nástrojem pro správu prostředků, ale vyžaduje poměrně hodně obřadnosti. Metody, které mají řadu prostředků ke správě, mohou být syntakticky zatíženy řadou příkazů using. Zátěž spojená se syntaxí je natolik významná, že většina pokynů pro styl kódování má explicitní výjimku ve vztahu ke složeným závorkám pro tento scénář.

Deklarace using zde odstraňuje většinu obřadu a staví jazyk C# na stejnou úroveň s jinými jazyky, které zahrnují bloky správy prostředků. Kromě toho vzorový přístup using umožňuje vývojářům rozšířit sadu typů, které se zde mohou zapojit. V mnoha případech odstranění potřeby tvoření obalových typů, které existují pouze k použití hodnot v příkazu using.

Společně tyto funkce umožňují vývojářům zjednodušit a rozšířit scénáře, ve kterých je možné using použít.

Podrobný návrh

deklarace klíčového slova using

Jazyk umožní přidání using do deklarace místní proměnné. Taková deklarace bude mít stejný účinek jako deklarování proměnné v příkazu using ve stejném umístění.

if (...) 
{ 
   using FileStream f = new FileStream(@"C:\source\using.md");
   // statements
}

// Equivalent to 
if (...) 
{ 
   using (FileStream f = new FileStream(@"C:\source\using.md")) 
   {
    // statements
   }
}

Životnost lokální proměnné using bude prodloužena do konce bloku, ve kterém je deklarována. Místní proměnné using budou poté odstraněny v opačném pořadí, ve kterém byly deklarovány.

{ 
    using var f1 = new FileStream("...");
    using var f2 = new FileStream("...");
    using var f3 = new FileStream("...");
    ...
    // Dispose f3
    // Dispose f2 
    // Dispose f1
}

Neexistují žádná omezení týkající se gotoani jiných konstrukcí řízení toku ve vztahu k deklaraci using. Místo toho kód funguje stejně jako pro ekvivalentní příkaz using:

{
    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;
    }
}

Místní proměnná deklarovaná v deklaraci using bude automaticky pouze pro čtení. To odpovídá chování lokálních proměnných deklarovaných v příkazu using.

Gramatika jazyka pro deklarace using bude následující:

local-using-declaration:
  'using' type using-declarators

using-declarators:
  using-declarator
  using-declarators , using-declarator
  
using-declarator:
  identifier = expression

Omezení týkající se deklarace using:

  • Nemusí se zobrazovat přímo uvnitř popisku case, ale musí být uvnitř bloku uvnitř popisku case.
  • Nemusí se zobrazit jako součást deklarace proměnné out.
  • Musí mít inicializátor pro každý deklarátor.
  • Místní typ musí být implicitně konvertibilní na IDisposable nebo musí splňovat vzor using.

na základě vzorů pomocí

Jazyk přidá koncept uvolnitelného vzoru pro typy ref struct: jedná se o ref struct, která má dostupnou metodu instance Dispose. Typy, které odpovídají jednorázovému vzoru, se mohou účastnit příkazu using nebo deklarace, aniž by musely implementovat IDisposable.

ref struct Resource
{ 
    public void Dispose() { ... }
}

using (var r = new Resource())
{
    // statements
}

To vývojářům umožní využívat using pro typy ref struct. Tyto typy nemůžou implementovat rozhraní v jazyce C# 8, a proto se nemůžou účastnit příkazů using.

Stejná omezení z tradičního příkazu using platí i zde: místní proměnné deklarované v using jsou jen pro čtení, hodnota null nezpůsobí vyvolání výjimky atd. Generování kódu se bude lišit pouze v tom, že před voláním Dispose nedojde k přetypování na IDisposable:

{
	  Resource r = new Resource();
	  try {
		    // statements
	  }
	  finally {
		    if (r != null) r.Dispose();
	  }
}

Aby bylo možné přizpůsobit jednorázový vzor, musí být metoda Dispose přístupným členem instance, bez parametrů a mít void návratový typ. Nemůže se jednat o metodu rozšíření.

Úvahy

V jazyce C# 8 nebyla implementována žádná z těchto aspektů.

popisky velkých a malých písmen bez bloků

using declaration není přípustný přímo uvnitř štítku case kvůli komplikacím kolem jeho skutečné životnosti. Jedním z možných řešení je prostě dát tomu stejnou životnost jako out var na stejném místě. Byla považována za dodatečnou složitost implementace funkce a snadné řešení (stačí přidat blok na popisek case) neodůvodnilo provedení této trasy.

Budoucí rozšíření

Opravené místní nastavení

Příkaz fixed má všechny vlastnosti příkazů using, které vyžadují schopnost mít using lokální proměnné. Je třeba zvážit rozšíření této funkce i na lokální komponenty fixed. Pravidla životnosti a řazení by měla platit stejně dobře pro using a fixed zde.