W języku C # using
instrukcja służy do deterministycznego usuwania zasobów bez oczekiwania na moduł odśmiecania. Na przykład można go użyć do:
Usuń polecenia SQL lub połączenia,
Zamknij strumienie, uwalniając źródło źródłowe jak plik,
Darmowe elementy GDI +,
itp.
Zauważyłem, że using
jest coraz częściej stosowany w przypadkach, w których nie ma nic do pozbycia się, ale tam, gdzie osoba dzwoniąca jest wygodniej napisać using
blok niż dwa osobne polecenia.
Przykłady:
MiniProfiler , napisany przez zespół Stack Overflow, używa
using
do oznaczania bloków do profilowania:using (profiler.Step("Name goes here")) { this.DoSomethingUseful(i - 1); }
Jednym alternatywnym podejściem byłoby posiadanie dwóch bloków:
var p = profiler.Start("Name goes here"); this.DoSomethingUseful(i - 1); profiler.Stop(p);
Innym podejściem byłoby użycie akcji:
profiler.Step("Name goes here", () => this.DoSomethingUseful(i - 1));
Program ASP.NET MVC wybrał również
using
formularze:<% using (Html.BeginForm()) { %> <label for="firstName">Name:</label> <%= Html.TextBox("name")%> <input type="submit" value="Save" /> <% } %>
Czy takie użycie jest właściwe? Jak to uzasadnić, biorąc pod uwagę, że istnieje kilka wad:
Początkujący byliby zagubieni, ponieważ takie użycie nie odpowiada temu, które wyjaśniono w książkach i specyfikacji językowej,
Kod powinien być wyrazisty. Tutaj cierpi ekspresja, ponieważ właściwe użycie
using
to pokazanie, że z tyłu znajduje się zasób, taki jak strumień, połączenie sieciowe lub baza danych, którą należy zwolnić bez czekania na śmieciarz.
źródło
using
: Ta ostatnia instrukcja (np.profiler.Stop(p)
) Nie jest gwarantowana, że zostanie wykonana w obliczu wyjątków i przepływu kontroli.Odpowiedzi:
Twoje ostatnie stwierdzenie - „właściwe użycie za pomocą to pokazanie, że z tyłu znajduje się zasób, taki jak strumień, połączenie sieciowe lub baza danych, które powinny zostać zwolnione bez czekania na śmietnik” jest niepoprawne, i powód jest podane w dokumentacji interfejsu IDisposable: http://msdn.microsoft.com/en-us/library/system.idisposable.aspx
Tak więc, jeśli twoja klasa korzysta z niezarządzanych zasobów, nie ma znaczenia, kiedy możesz lub nie chcesz, aby GC się wydarzyło - nie ma to nic wspólnego z GC, ponieważ niezarządzane zasoby nie są GC'owane ( https: // stackoverflow. com / pytania / 3607213 / what-is-mean-by-managed-vs.-unmanaged-resources-in-net ).
Tak więc celem „używania” nie jest uniknięcie czekania na GC, ale wymuszenie zwolnienia tych niezarządzanych zasobów teraz , zanim instancja klasy znajdzie się poza zasięgiem i zostanie wywołana jej finalizacja. Jest to ważne z powodów, które powinny być oczywiste - niezarządzany zasób może być zależny od innych niezarządzanych zasobów, a jeśli zostaną one zutylizowane (lub sfinalizowane) w niewłaściwej kolejności, mogą wystąpić Złe rzeczy.
Jeśli więc instancja klasy w używanym bloku korzysta z niezarządzanych zasobów, to odpowiedź brzmi tak - jest właściwa.
Zauważ jednak, że IDisposable nie nakazuje, aby służył on jedynie do uwalniania niezarządzanych zasobów - tylko że jest to jego główny cel. To może być tak, że autor tej klasy ma pewne działanie, które chcą wymusić dzieje się w określonym czasie, a także wdrażaniu IDisposable może być sposobem na uzyskanie tak się stało, ale czy nie jest to eleganckie rozwiązanie jest coś, co może odpowiedź udzielana jest indywidualnie dla każdego przypadku.
Niezależnie od tego, użycie „using” oznacza, że klasa implementuje IDisposable, więc nie narusza to ekspresji kodu; w gruncie rzeczy jasno pokazuje, co się dzieje.
źródło
Zastosowanie
using
implikuje obecnośćDispose()
metody. Inni programiści przyjmą, że taka metoda istnieje na obiekcie. W związku z tym, jeśli przedmiot nie jest jednorazowy, nie powinieneś go używaćusing
.Klarowność kodu jest królem. Pomiń
using
lub zaimplementujIDisposable
na obiekcie.Wygląda na to, że MiniProfiler używa
using
jako mechanizmu „ogrodzenia” profilowanego kodu. Jest w tym trochę zasług; przypuszczalnie MiniProfiler albo wywołujeDispose()
stoper, albo stoper jest zatrzymywany, gdy obiekt MiniProfiler wykracza poza zakres.Mówiąc bardziej ogólnie, należy wywoływać,
using
gdy pewnego rodzaju finalizacja musi nastąpić automatycznie. Dokumentacjahtml.BeginForm
stwierdza, że gdy metoda jest używana wusing
instrukcji, renderuje</form>
znacznik zamykający na końcuusing
bloku.To niekoniecznie oznacza, że nadal nie jest to nadużycie.
źródło
IDisposable
/Dispose()
pomimo braku możliwości dysponowania w sensie opisanym przez OP?Dispose
jest to konieczne,using
aby w ogóle mieć sens (niezależnie od tego, czy jest to właściwe). Wszystkie przykłady OP są implementowaneDispose
, prawda? I IIUC, pytanie brzmi, czy to prawda, że te klasy używająDispose
, a nie jakiejś innej metody (jak wStop()
przypadku MiniProfiler).using
jest bezpieczny w przypadku błędów i wyjątków. ZapewniaDispose()
to, że zostanie nazwany niezależnie od błędów popełnianych przez programistę. Nie przeszkadza to w wychwytywaniu lub obsłudze wyjątków, aleDispose()
metoda jest wykonywana rekurencyjnie w górę stosu, gdy zostanie zgłoszony wyjątek.Obiekty, które implementują,
IDispose
ale nie mają nic do pozbycia się po ich zakończeniu. Są w najlepszym razie, sprawdzają w przyszłości swój projekt. Abyś nie musiał refaktoryzować kodu źródłowego, kiedy w przyszłości będą musieli się czegoś pozbyć.źródło