Dlaczego nie ma RAII in.NET?

Będąc przede wszystkim programistą C++, Brak RAII (pozyskiwanie zasobów jest inicjalizacją) w Javie i. NET zawsze mi przeszkadzał. Fakt, że ciężar sprzątania jest przenoszony z class writer do jego konsumenta (za pomocą try finally lub. NET ' s using construct) wydaje się być znacznie gorszy.

Rozumiem, dlaczego w Javie nie ma wsparcia dla RAII, ponieważ wszystkie obiekty znajdują się na stercie, a garbage collector z natury nie wspiera deterministycznego destrukcji, ale w. Net z wprowadzeniem typów wartości (struct) mamy (pozornie) idealnego kandydata do RAII. Typ wartości, który jest tworzony na stosie, ma dobrze zdefiniowany zakres i można użyć semantyki C++ destructor. Jednakże CLR nie pozwala typowi wartości na posiadanie destruktora.

Moje losowe wyszukiwania znalazły jeden argument, że jeśli typ wartości jest boxed {[13] } podlega jurysdykcji garbage collector i dlatego jego zniszczenie staje się niedeterministyczne. Uważam, że ten argument nie jest wystarczająco silny, korzyści RAII są wystarczająco duże, aby powiedzieć, że typ wartości z destruktorem nie może być boxowany (lub używany jako członek klasy).

Krótko mówiąc, moje pytanie brzmi: Czy istnieją inne powody, dla których typy wartości nie mogą być użyte w celu wprowadzenia RAII do. NET? (a może uważasz, że mój argument o oczywistych zaletach RAII jest błędny?)

Edit: musiałem nie sformułować pytania widać, że pierwsze cztery odpowiedzi nie trafiły w sedno. Ja wiem o Finalize i jego niedeterministycznych cechach, wiem o using konstrukcji i czuję, że te dwie opcje są gorsze od RAII. using jest jeszcze jedna rzecz, którą konsument klasy musi pamiętać (ile osób zapomniało umieścić StreamReader w bloku using?). Moje pytanie jest filozoficzne na temat konstrukcji języka, dlaczego tak jest i czy można go poprawić?

Na przykład z ogólnym deterministycznie destruktywny typ wartości i może sprawić, że słowa kluczowe using i lock będą zbędne (możliwe do osiągnięcia przez klasy biblioteczne):

    public struct Disposer<T> where T : IDisposable
    {
        T val;
        public Disposer(T t) { val = t; }
        public T Value { get { return val; } }
        ~Disposer()  // Currently illegal 
        {
            if (val != default(T))
                val.Dispose();
        }
    }

Nie mogę powstrzymać się od zakończenia cytatem apropos, który kiedyś widziałem, ale obecnie nie mogę znaleźć jego pochodzenia.

Możesz wziąć moją deterministyczną destrukcję, kiedy moja zimna Martwa ręka wyjdzie poza zasięg. -- Anon
Author: Motti, 2008-10-06

7 answers

Lepszym tytułem byłoby "dlaczego nie ma RAII w C# / VB". C++ / CLI (ewolucja języka C++) ma RAII dokładnie w tym samym znaczeniu co C++. To wszystko tylko cukier składniowy dla tego samego wzorca finalizacji, którego używa reszta języków CLI( destruktory w zarządzanych obiektach dla C++ / CLI są efektywnie finalizatorami), ale jest.

You might like http://blogs.msdn.com/hsutter/archive/2004/07/31/203137.aspx

 16
Author: Adam Wright,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-06 08:04:17

Doskonałe pytanie i takie, które bardzo mi przeszkadzało. Wydaje się, że korzyści płynące z RAII są postrzegane bardzo różnie. Z mojego doświadczenia z. Net, brak deterministycznego (lub przynajmniej wiarygodnego) gromadzenia zasobów jest jedną z głównych wad. W rzeczywistości. NET zmusił mnie kilka razy do zatrudniania całych architektur do radzenia sobie z niezarządzanymi zasobami, które Mogą (ale nie mogą) wymagać jawnego zbierania. Co, oczywiście, jest ogromną wadą, ponieważ sprawia, że ogólnie Architektura trudniejsza i odciąga uwagę klienta od bardziej centralnych aspektów.

 13
Author: Konrad Rudolph,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-06 09:44:41

Brian Harry ma fajny post o racjonalnościach tutaj .

Oto fragment:

A co z finalizacją deterministyczną i typami wartości (strukturami)?

-------------- widziałem wiele pytań o struktury mające destruktorów, itp. To jest warte skomentuj. Istnieją różne problemy, dlaczego niektóre języki nie weź je.

(1) Skład-nie dają Ci życie deterministyczne w ogólności Etui na te same rodzaje kompozycji powody opisane powyżej. Dowolne Klasa niedeterministyczna zawierająca jeden nie wywołałby destruktora, dopóki nie i tak został sfinalizowany przez GC.

(2) konstruktory kopiujące-jedno miejsce gdzie naprawdę byłoby miło jest w stos przydzielonych mieszkańców. Będą scoped do metody i wszystko będzie świetnie. Niestety, aby uzyskać to naprawdę działa, trzeba również dodaj konstruktory kopiujące i wywołaj je za każdym razem, gdy instancja jest zrozumiałem. Jest to jeden z najbrzydszych i najbardziej skomplikowane rzeczy o C++. You end up getting code executing all over the miejsce, w którym się tego nie spodziewasz. Informatyka powoduje szereg problemów językowych. Niektórzy projektanci języka wybrali trzymaj się od tego z daleka.

Powiedzmy, że stworzyliśmy struktury z destruktorów, ale dodano kilka ograniczenia, aby ich zachowanie sensowne w obliczu problemów powyżej. Ograniczenia byłyby coś w stylu:

(1) możesz zadeklarować je tylko jako lokalne zmienne.

(2) można je tylko przekazać by-ref

(3) nie możesz ich przypisać, ty ma dostęp tylko do pól i wywołania metody na nich.

(4) You can ' t box oni.

(5) problemy z ich wykorzystaniem przez Refleksji (późne wiązanie), ponieważ to zwykle wiąże się z boksem.

Maybe more, ale to dobry początek.

Jaki z tego pożytek? Would faktycznie tworzysz plik lub a Klasa połączenia z bazą danych, która może Być używane tylko jako zmienna lokalna? I nie wierzę, że ktokolwiek by to zrobił. Zamiast tego stworzyłbyś połączenie ogólnego przeznaczenia, a następnie Utwórz automatycznie zniszczoną owijkę dla Użyj jako zmienna lokalna o zasięgu. Na rozmówca wybierze wtedy to, co chciał użyć. Uwaga rozmówca dokonał decyzji i nie jest to do końca zamknięty w samym obiekcie. Biorąc pod uwagę, że przydałoby ci się coś podobnie jak propozycje nadchodzące up in a kilka sekcji.

Zamiennikiem RAII w. NET jest using-pattern, który działa prawie tak samo dobrze, gdy się do niego przyzwyczaisz.

 13
Author: Rasmus Faber,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-20 20:42:31

Najbliżej tego jest bardzo ograniczony operator stackalloc.

 1
Author: leppie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-06 09:27:57

Jest kilka podobnych wątków, jeśli ich szukasz, ale zasadniczo sprowadza się to do tego, że jeśli chcesz RAII na.Net po prostu zaimplementuj IDisposable type i użyj instrukcji "using", aby uzyskać deterministyczną dyspozycję. W ten sposób wiele z tych samych ideomów może być zaimplementowanych i używanych tylko w nieco bardziej słowny sposób.

 1
Author: Torbjörn Gyllebring,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-06 09:32:45

IMHO, wielkie rzeczy, które VB.net i C # potrzebne są:

  1. deklaracja "using" dla pól, która spowodowałaby, że kompilator wygeneruje kod, aby pozbyć się wszystkich pól w ten sposób oznaczonych. Domyślnym zachowaniem powinno być, aby kompilator sprawił, że klasa implementuje IDisposable, jeśli nie, lub wstawić logikę usuwania przed rozpoczęciem głównej procedury usuwania dla dowolnego z wielu wspólnych IDisposal wzorców implementacji, lub użyć atrybutu, aby określić, że rzeczy usuwania powinien iść w rutynie z konkretną nazwą.
  2. sposób deterministycznego usuwania obiektów, których konstruktory i/lub inicjalizatory pól rzucają wyjątek, albo przez domyślne zachowanie (wywołanie domyślnej metody usuwania) lub zachowanie niestandardowe (wywołanie metody o określonej nazwie).
  3. dla vb.net, automatycznie wygenerowana metoda null out all WithEvent fields.

Wszystko to można całkiem dobrze wkomponować w vb.net, i nieco mniej dobrze w C#, ale pierwszorzędne wsparcie dla nich poprawiłoby oba języki.

 1
Author: supercat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-12-14 04:16:09

Możesz zrobić formę RAII w.Net i Javie używając metod finalize (). Przeciążenie finalize() jest wywoływane przed czyszczeniem klasy przez GC, więc może być użyte do czyszczenia wszelkich zasobów, które absolutnie nie powinny być przechowywane przez klasę (muteksy, gniazda, uchwyty plików, itp.). Nie jest to jednak deterministyczne.

Z. NET możesz zrobić część tego deterministycznie z interfejsem IDisposable i słowem kluczowym using, ale to ma ograniczenia (używanie konstruktu, gdy jest używane wymagane dla zachowania deterministycznego, nadal brak deterministycznej dealokacji pamięci, nie używane automatycznie w klasach itp.).

I tak, czuję, że jest miejsce na pomysły RAII do wprowadzenia do. NET i innych zarządzanych języków, chociaż dokładny mechanizm można dyskutować bez końca. Jedyną alternatywą, którą mogłem zobaczyć byłoby wprowadzenie GC, które mogłyby obsługiwać arbitralne czyszczenie zasobów (nie tylko pamięć), ale wtedy masz problemy, gdy wspomniane zasoby absolutnie muszą być wydany deterministycznie.

 -3
Author: workmad3,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-06 09:31:45