Wiem jak zwalniać zasoby zajmowane przez pędzle, pióra itd.
Utworzyłem własną kontrolkę (public class CustomControl: Control), na niej wykonane zostały pewne operacje rysowania (tekst, obrazki) w zdarzeniu Paint (protected override void OnPaint(PaintEventArgs e)).
W trybie wizualnym kontrolkę tą przesunąłem na Formę.
Mogę oczywiście po zakończeniu rysowania w zdarzeniu Paint klasy CustomControl wywołać bmp.Dispose() itd, ale w przykładach gdzie mam animacje tworzenie i zwalnianie zasobów w Paint, które wywoływane jest co chwilę nie ma sensu.
Moje pytanie polega na tym czy zasoby zajmowane przez obiekty (Graphics, Bitmap, Pen, Brush itd) przez klasę CustomControl mogę zwolnić przy zamykaniu Formularza (Form1)?
Utworzyłem w tej klasie funkcję:
public void zwolnij()
{
bmp.Dispose();
pen.Dispose();
}
Radziłbym dać zwolnienie w destruktorze. Nie zawsze zamykanie formatki jednoznacznie związane z jej niszczeniem, na przykład odpalenie w trybie modalnym.
Nie zupełnie to tak jest. To zdarzenie może zostać odwołane przez zmianę właściwości Cancel na true w parametrze CancelEventArgs przekazanym do zdarzenia. Jeżeli mamy pewną hierarchie okienek np MDI to może się okazać że zamknięcie zostanie “odwołane” przez jakieś okienko podrzędne, zaś okienko główne już zwolni zasoby. Owszem to niezbyt często zdarzający się scenariusz ale wg mnie lepiej dmuchać na zimno tym bardziej że wszystkie obiekty Pen, Brush itp są threadsafety więc bezpiecznie mogą zostać zwolnione w destruktorze klasy.
Czy wywołanie jej w zdarzeniu FormClosed() Form1 załatwi sprawę, czy fragment zawarty pomiędzy zwalniający poszczególne obiekty jest wymagany, czy też ta metoda sama załatwi sprawę?
Zdarzenie FormClosed jest generowane tylko raz, po zamknięciu okna i wtedy należy zwalniać zasoby. Zdarzenie FormClosing może być generowane wielokrotnie.
Destruktorem w języku C# jest metoda Dispose. Metoda ta nie jest automatycznie wołana po zamknięciu formy i aby bezzwłocznie zwolnić zasoby, trzeba ją wołać ręcznie.
Destruktor w C# jest sprowadzany do metody Finalize(), nie Dispose().
Metoda Dispose() pochodzi z interfejsu IDisposable() i jest sensownym miejscem zwalniania zasobów, gdy jest taka potrzeba. Obiekty klas implementujących IDisposable można ładnie obsługiwać w sekcjach using.
Finalize() zrobi to, co Dispose(), gdy zostanie wywołana przez GC. To on odpowiada za zarządzanie pamięcią, nie programista.
Nie ma sensu zwalniania zasobów zarządzanych, tym zajmuje się GC.
Problem jest sztuczny - klasa Control implementuje metodę Dispose(), zapewnia zatem zwolnienie swoich zasobów z automatu, gdy zajdzie taka potrzeba. Niczego nie trzeba dodatkowo zwalniać.
To ty głupoty wypisujesz, ponieważ destruktorem w C# jest destruktor a nie metoda Dispose(). Oprócz tego że nie masz pojęcia o czym piszesz , to jeszcze sarkazmu nie pojmujesz.
W języku C# nie ma destruktora jako takiego, jego rolę pełni metoda Dispose. W języku C++/CLI masz destruktor i finalizer, tak więc finalizer nie jest destruktorem.
GC nie powinien odpowiadać za zwalnianie innych zasobów niż pamięć.
Bzdura, gdyż GC działa kiedy mu się podoba. Nie można na nim polegać w przypadku zwalniania ograniczonych zasobów.
Problem nie jest sztuczny, gdyż klasa Control zwalnia tylko swoje zasoby. Takich zasobów jak Pen czy Brush nie zwolni.
W normalnym rysowaniu używam instrukcji using(), ale nie wydaje mi się dobrym pomysłem (tak sądzę), aby w zdarzeniu OnPaint() wywoływanym co 10ms przez timer stosować using() dla ok 10 różnych obiektów graficznych, aby co chwilę były one tworzone i usuwane. Chyba że nie tak jak trzeba to pojmuję.
Bardzo niedobre podejście, zabierz ten static i będzie dobrze. static oznacza jeden egzemplarz na wszystkie obiekty tej klasy. Jeżeli będziesz miał dwie takie kontrolki na różnych formatkach to zamknięcie jednej formatki spowoduje zwolnienie obiektu “p” ponieważ istnieje tylko jeden.
Jeżeli tymi obiektami nie są duże bitmapy, to śmiało można tworzyć je podczas rysowania.
Nie możesz na takim kodzie polegać, gdyż nie wiadomo kiedy finalizer się wykona.
Nie muszę czytać dokumentów, gdyż język C# bardzo dobrze znam. To, że Microsoft w języku C# pomieszał destruktor z finalizerem, jest faktem bardzo dobrze znanym. Widać to bardzo dobrze na przykładzie języka C++/CLI, gdzie finalizer nie jest destruktorem.