Uważam to za nadużycie instrukcji using. Wiem, że na tym stanowisku jestem w mniejszości.
Uważam to za nadużycie z trzech powodów.
Po pierwsze, ponieważ spodziewam się, że „używanie” jest używane do korzystania z zasobu i pozbycia się go, gdy skończysz . Zmiana stanu programu nie wykorzystuje zasobu, a zmiana go z powrotem nie powoduje usunięcia niczego. Dlatego „używanie” do mutowania i przywracania stanu jest nadużyciem; kod wprowadza w błąd zwykłego czytelnika.
Po drugie, ponieważ oczekuję, że „używanie” będzie używane z grzeczności, a nie z konieczności . Powodem, dla którego używasz "using" do pozbycia się pliku, gdy skończysz z nim, nie jest to, że jest to konieczne , ale dlatego, że jest to grzeczne - ktoś inny może czekać na użycie tego pliku, więc mówi: „gotowe teraz ”jest moralnie poprawną rzeczą do zrobienia. Spodziewam się, że powinienem być w stanie refaktoryzować „użycie”, tak aby zużyty zasób był dłużej zatrzymywany i usuwany później, a jedynym skutkiem takiego działania jest nieznaczne utrudnienie innych procesów, . Blok „używający”, który ma semantyczny wpływ na stan programu ponieważ ukrywa on ważny , wymagała mutacji stanu programu w konstrukcji, która wygląda tak, jakby istniała dla wygody i grzeczności, a nie z konieczności.
Po trzecie, działania twojego programu są określane przez jego stan; właśnie potrzeba starannego manipulowania stanem jest właśnie powodem, dla którego prowadzimy tę rozmowę. Zastanówmy się, jak możemy przeanalizować Twój oryginalny program.
Gdybyś miał to przynieść do przeglądu kodu w moim biurze, pierwsze pytanie, które zadałbym, brzmiało: „czy naprawdę poprawne jest blokowanie frobble, jeśli zostanie zgłoszony wyjątek?” Z twojego programu jasno wynika, że ta rzecz agresywnie ponownie blokuje frobble bez względu na to, co się stanie. Czy to prawda? Zgłoszono wyjątek. Program jest w nieznanym stanie. Nie wiemy, czy Foo, Fiddle czy Bar rzucali, dlaczego rzucali, ani jakie mutacje przeprowadzali w innym stanie, które nie zostało oczyszczone. Czy możesz mnie przekonać , że w tej okropnej sytuacji zawsze dobrze jest ponownie zamknąć zamek?
Może tak jest, może nie jest. Chodzi mi o to, że mając kod w takiej postaci, w jakiej został pierwotnie napisany, recenzent kodu wie, aby zadać pytanie . W kodzie używającym słowa „using” nie umiem zadawać pytania; Zakładam, że blok "using" przydziela zasób, używa go trochę i grzecznie pozbywa się go po zakończeniu , a nie, że nawias zamykający bloku "using" mutuje mój stan programu w wyjątkowych okolicznościach, gdy jest dowolnie wiele warunki zgodności stanu programu zostały naruszone.
Użycie bloku „using” w celu uzyskania efektu semantycznego powoduje, że program jest fragmentem:
}
niezwykle znaczące. Kiedy patrzę na tę pojedynczą klamrę zamykającą, nie myślę od razu, że „ta klamra ma skutki uboczne, które mają daleko idący wpływ na globalny stan mojego programu”. Ale kiedy nadużywasz „używania” w ten sposób, nagle to robi.
Drugą rzeczą, którą chciałbym zapytać, gdybym zobaczył twój oryginalny kod, jest „co się stanie, jeśli wyjątek zostanie zgłoszony po odblokowaniu, ale przed wprowadzeniem próby?” Jeśli używasz niezoptymalizowanego zestawu, kompilator mógł wstawić instrukcję no-op przed próbą i jest możliwe, że wyjątek przerwania wątku wystąpi w przypadku braku operacji. Jest to rzadkie, ale zdarza się w prawdziwym życiu, szczególnie na serwerach internetowych. W takim przypadku następuje odblokowanie, ale blokada nigdy się nie dzieje, ponieważ wyjątek został zgłoszony przed próbą. Jest całkowicie możliwe, że ten kod jest podatny na ten problem i powinien zostać napisany
bool needsLock = false;
try
{
// must be carefully written so that needsLock is set
// if and only if the unlock happened:
this.Frobble.AtomicUnlock(ref needsLock);
blah blah blah
}
finally
{
if (needsLock) this.Frobble.Lock();
}
Znowu, może tak, może nie, ale wiem mogę zadać pytanie . W przypadku wersji używającej jest podatny na ten sam problem: wyjątek przerwania wątku może zostać zgłoszony po zablokowaniu Frobble, ale przed wprowadzeniem regionu chronionego przed próbą skojarzonego z użyciem. Ale z wersją „używającą” zakładam, że jest to „i co z tego?” sytuacja. Szkoda, że tak się stanie, ale zakładam, że „używanie” jest tylko po to, aby być uprzejmym, a nie po to, aby mutować niezwykle ważny stan programu. Zakładam, że jeśli jakiś straszny wyjątek przerwania wątku zdarzy się dokładnie w niewłaściwym czasie, to cóż, moduł odśmiecania pamięci wyczyści ten zasób, uruchamiając finalizator.