"wzorcowe użycie" i "deklaracje dotyczące użycia"
Notatka
Ten artykuł jest specyfikacją funkcji. Specyfikacja służy jako dokument projektowy dla funkcji. Zawiera proponowane zmiany specyfikacji wraz z informacjami wymaganymi podczas projektowania i opracowywania funkcji. Te artykuły są publikowane do momentu sfinalizowania proponowanych zmian specyfikacji i włączenia ich do obecnej specyfikacji ECMA.
Mogą wystąpić pewne rozbieżności między specyfikacją funkcji a ukończoną implementacją. Te różnice są przechwytywane w odpowiednich spotkania projektowego języka (LDM).
Więcej informacji na temat procesu wdrażania specyfikacji funkcji można znaleźć w standardzie języka C# w artykule dotyczącym specyfikacji .
Problem z liderem: https://github.com/dotnet/csharplang/issues/114
Streszczenie
Język doda dwie nowe funkcje wokół instrukcji using
, aby ułatwić zarządzanie zasobami: using
powinien rozpoznawać wzorzec jednorazowego użytku oprócz IDisposable
oraz dodać deklarację using
do języka.
Motywacja
Oświadczenie using
jest skutecznym narzędziem do zarządzania zasobami obecnie, ale wymaga sporo formalności. Metody, które mają wiele zasobów do zarządzania, mogą się stać składniowo skomplikowane przez serię instrukcji using
. To obciążenie składniowe jest na tyle duże, że większość wytycznych dotyczących stylu kodowania wyraźnie przewiduje wyjątek dotyczący nawiasów klamrowych dla tego scenariusza.
Deklaracja using
usuwa dużą część zbędnych formalności i stawia język C# na równi z innymi językami, które zawierają bloki zarządzania zasobami. Ponadto oparty na wzorcu using
umożliwia deweloperom rozwijanie zestawu typów, które mogą uczestniczyć tutaj. W wielu przypadkach oznacza to usunięcie konieczności tworzenia typów otoki, które istnieją wyłącznie po to, aby umożliwić użycie wartości w instrukcji using
.
Te funkcje pozwalają deweloperom uprościć i rozszerzyć scenariusze, w których można zastosować using
.
Szczegółowy projekt
przy użyciu deklaracji
Język umożliwi dodanie using
do deklaracji zmiennej lokalnej. Taka deklaracja będzie miała taki sam efekt jak deklarowanie zmiennej w instrukcji using
w tej samej lokalizacji.
if (...)
{
using FileStream f = new FileStream(@"C:\source\using.md");
// statements
}
// Equivalent to
if (...)
{
using (FileStream f = new FileStream(@"C:\source\using.md"))
{
// statements
}
}
Okres istnienia using
lokalnego będzie rozciągać się do końca zakresu, w którym jest zadeklarowany.
using
lokalne zmienne zostaną następnie usunięte w odwrotnej kolejności, w której je zadeklarowano.
{
using var f1 = new FileStream("...");
using var f2 = new FileStream("...");
using var f3 = new FileStream("...");
...
// Dispose f3
// Dispose f2
// Dispose f1
}
Nie ma żadnych ograniczeń dotyczących goto
ani żadnej innej konstrukcji przepływu sterowania w obliczu deklaracji using
. Zamiast tego kod działa tak samo jak w przypadku równoważnej instrukcji 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;
}
}
Lokalna zmienna zadeklarowana w deklaracji lokalnej using
stanie się niejawnie tylko do odczytu. Jest to zgodne z zachowaniem zmiennych lokalnych określonych w instrukcji using
.
Gramatyka języka dla deklaracji using
będzie następująca:
local-using-declaration:
'using' type using-declarators
using-declarators:
using-declarator
using-declarators , using-declarator
using-declarator:
identifier = expression
Ograniczenia dotyczące deklaracji using
:
- Może nie pojawiać się bezpośrednio wewnątrz etykiety
case
, ale zamiast tego musi znajdować się w bloku wewnątrz etykietycase
. - Może nie być wyświetlana jako część deklaracji zmiennej
out
. - Musi mieć inicjalizator dla każdego deklaratora.
- Typ lokalny musi być niejawnie konwertowany na
IDisposable
lub spełniać wzorzecusing
.
oparte na wzorcu przy użyciu
Język doda pojęcie jednorazowego wzorca dla typów ref struct
: jest to ref struct
, który ma dostępną metodę wystąpienia Dispose
. Typy pasujące do wzorca jednorazowego mogą brać udział w deklaracji lub instrukcji using
bez potrzeby implementacji IDisposable
.
ref struct Resource
{
public void Dispose() { ... }
}
using (var r = new Resource())
{
// statements
}
Umożliwi to programistom wykorzystanie using
dla typów ref struct
. Te typy nie mogą implementować interfejsów w języku C# 8 i dlatego nie mogą uczestniczyć w instrukcjach using
.
Te same ograniczenia dotyczące tradycyjnej instrukcji using
mają zastosowanie również: zmienne lokalne zadeklarowane w using
są tylko do odczytu, wartość null
nie spowoduje zgłoszenia wyjątku itp. Generowanie kodu będzie inne tylko w tym, że nie będzie rzutowania do IDisposable
przed wywołaniem Dispose:
{
Resource r = new Resource();
try {
// statements
}
finally {
if (r != null) r.Dispose();
}
}
Aby dopasować wzorzec jednorazowego użycia, metoda Dispose
musi być dostępnym składowym obiektem, bezparametrowa i mieć typ zwracany void
. Nie może to być metoda rozszerzenia.
Zagadnienia dotyczące
Żadna z tych kwestii nie została zaimplementowana w języku C# 8
etykiety przypadku bez bloków
using declaration
jest nielegalne bezpośrednio wewnątrz etykiety case
ze względu na komplikacje związane z jego faktycznym czasem trwania. Jednym z potencjalnych rozwiązań jest po prostu nadanie mu tego samego okresu istnienia co out var
w tej samej lokalizacji. Uznano, że dodatkowa złożoność implementacji tej funkcji i prostota obejścia problemu (wystarczy dodać blok do etykiety case
) nie uzasadniają wybrania tej ścieżki.
Przyszłe rozszerzenia
ustalone lokalne ustawienia
Instrukcja fixed
ma wszystkie właściwości instrukcji using
, które motywowały możliwość posiadania lokalnych using
. Należy również rozważyć rozszerzenie tej funkcji na fixed
lokalne. Reguły okresu istnienia i porządkowania powinny być stosowane równie dobrze dla using
i fixed
tutaj.
C# feature specifications