07/05/2010

ShowDialog i zwalnianie zasobów

Home

TestForm form = new TestForm();

if (form.ShowDialog() == DialogResult.OK)
{
  ...
}
Czy powyższy króciutki fragment kodu powodujący wyświetlenie okna dialogowego jest poprawny? Niestety, jeszcze do niedawna powiedziałbym bez mrugnięcia oka, że oczywiście tak. Niestety ponieważ ta odpowiedź jest niepoprawna. Do tego aby ten kod był poprawny brakuje niewielkiej ale za to bardzo istotnej rzeczy i zostało to pokazane poniżej:

using(TestForm form = new TestForm())
{
  if (form.ShowDialog() == DialogResult.OK)
  {
    ...
  }
}
Zamiast klauzuli using można oczywiście wywołać Dispose. Dlaczego jednak jawne zwolnienie zasobów jest w ogóle potrzebne? Czy to oznacza, że za każdym razem kiedy chcemy wyświetlić jakieś okno musimy pamiętać o klauzuli using?

Odpowiedź brzmi nie, jest to konieczne tylko jeśli wyświetlamy okno dialogowe. W takim wypadku po jego zamknięciu nie następuje wywołanie metody Close, która zwolni za nas zasoby. Dzięki temu możemy użyć tego samego okna ponownie. Nie jest to żadna wiedza tajemna i można o tym przeczytać w dokumentacji metody ShowDialog:

Unlike modeless forms, the Close method is not called by the .NET Framework when the user clicks the close form button of a dialog box or sets the value of the DialogResult property.

Kolejny raz przekonuję się, że nawet jeśli czegoś używamy bardzo często i jest to dla nas coś prostego i oczywistego to nie znaczy to, że robimy to na 100% dobrze :)

5 comments:

Anonymous said...

"Zamiast klauzuli using można oczywiście wywołać Dispose" - oczywiście można, ale klauzula using zapewnia właściwe zwolnienie zasobów (wykonanie Dispose()) nawet podczas obsługi wyjątku, więc żeby nie robić tego wszystkiego ręcznie (bo samo gołe wywołanie Dispose() tego nie zapewnia) stosujmy using

demikaze said...

"Zamiast klauzuli using można oczywiście wywołać Dispose" - oczywiście można, ale klauzula using zapewnia właściwe zwolnienie zasobów (wykonanie Dispose()) nawet podczas obsługi wyjątku, więc żeby nie robić tego wszystkiego ręcznie (bo samo gołe wywołanie Dispose() tego nie zapewnia) stosujmy using

Michał Komorowski said...

Pisząc, że można wywołać Dispose użyłem skrótu myślowego. Jeśli chcemy jawnie wywołać Dispose to powinniśmy oczywiście dodatkowo zastosować blok try/finally itd. Swoją drogą użycie klauzuli using przekłada się właśnie na taki blok try/finally.

Marcin Rybacki said...

ale smaczek :) Dzięki :)

Anonymous said...

sprawa wyglada inaczej w WPF. WPF sam sie o to troszczy przy wywolaniu Close() na danym oknie. Jeśli jednak chcialibyśmy używać using to wtedy to specyficzne okno musi implementować IDisposable

Post a comment