Dlaczego nie ma RAII w .NET?
Bycie przede wszystkim deweloperem C ++ nieobecnościRAII (Resource Acquisition Is Initialization) w Javie i .NET zawsze mi przeszkadzało. Fakt, że ciężar czyszczenia jest przenoszony z autora klasy na konsumenta (za pomocątry finally
lub .NETusing
skonstruować) wydaje się być znacznie gorszy.
Widzę, dlaczego w Javie nie ma obsługi RAII, ponieważ wszystkie obiekty znajdują się na stercie, a garbage collector z natury nie obsługuje deterministycznego niszczenia, ale w .NET wraz z wprowadzeniem typów wartości (struct
) mamy (pozornie) idealnego kandydata na RAII. Typ wartości utworzony na stosie ma dobrze zdefiniowany zakres i można użyć semantyki destruktora C ++. Jednak CLR nie zezwala, aby typ wartości miał destruktor.
Moje przypadkowe wyszukiwania znalazły jeden argument, jeśli typem wartości jestzapakowane podlega jurysdykcji zbieracza śmieci i dlatego jego zniszczenie staje się niedeterministyczne. Uważam, że ten argument nie jest wystarczająco silny, zalety RAII są wystarczająco duże, by powiedzieć, że typu wartości z destruktorem nie można umieścić w pudełku (ani użyć jako członka klasy).
Krótko mówiąc, moje pytanie brzmi: czy są jakieś inne powody, dla których typy wartości nie mogą być użyte do wprowadzenia RAII do .NET? (czy myślisz, że mój argument o oczywistych zaletach RAII jest wadliwy?)
Edytować: Nie sformułowałem tego pytania jasno, ponieważ pierwsze cztery odpowiedzi nie trafiły w sedno. jawiedzieć oFinalize
i jego niedeterministyczne cechy, wiem ousing
konstrukt i uważam, że te dwie opcje są gorsze od RAII.using
to jeszcze jedna rzecz, o której konsument klasy musi pamiętać (ile osób zapomniało umieścićStreamReader
wusing
blok?). Moje pytanie jest filozoficzne na temat projektowania języka, dlaczego tak jest i czy można je ulepszyć?
Na przykład z typowym, deterministycznie niszczącym typem wartości mogę zrobićusing
ilock
słowa kluczowe redundantne (osiągalne 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ę przestać kończyć się cytatem apropos, który kiedyś widziałem, ale obecnie nie mogę znaleźć jego źródła.
Możesz zniwelować moje deterministyczne zniszczenie, gdy moja zimna martwa ręka zniknie z zasięgu. -Zaraz