Okres istnienia obiektów: w jaki sposób obiekty są tworzone i niszczone (Visual Basic)

Wystąpienie klasy , obiektu, jest tworzone przy użyciu słowa kluczowego New . Zadania inicjowania często muszą być wykonywane na nowych obiektach przed ich zastosowaniem. Typowe zadania inicjowania obejmują otwieranie plików, łączenie się z bazami danych i odczytywanie wartości kluczy rejestru. Visual Basic steruje inicjowaniem nowych obiektów przy użyciu procedur nazywanych konstruktorami (specjalne metody, które umożliwiają kontrolę nad inicjowaniem).

Po opuszczeniu zakresu obiekt jest zwalniany przez środowisko uruchomieniowe języka wspólnego (CLR). Visual Basic steruje wydawaniem zasobów systemowych przy użyciu procedur nazywanych destruktorami. Razem konstruktory i destruktory obsługują tworzenie niezawodnych i przewidywalnych bibliotek klas.

Używanie konstruktorów i destruktorów

Konstruktory i destruktory kontrolują tworzenie i niszczenie obiektów. Procedury Sub New i Sub Finalize w Visual Basic inicjują i niszczą obiekty; zastępują Class_Initialize metody i Class_Terminate używane w języku Visual Basic 6.0 i starszych wersjach.

Sub New

Konstruktor Sub New może działać tylko raz po utworzeniu klasy. Nie można go wywołać jawnie w dowolnym miejscu innym niż w pierwszym wierszu kodu innego konstruktora z tej samej klasy lub z klasy pochodnej. Ponadto kod w metodzie Sub New zawsze jest uruchamiany przed jakimkolwiek innym kodem w klasie. Program Visual Basic niejawnie tworzy Sub New konstruktor w czasie wykonywania, jeśli nie zdefiniujesz Sub New jawnie procedury dla klasy.

Aby utworzyć konstruktor dla klasy, utwórz procedurę o nazwie Sub New w dowolnym miejscu w definicji klasy. Aby utworzyć konstruktor sparametryzowany, określ nazwy i typy danych argumentów tak Sub New samo jak argumenty dla każdej innej procedury, jak w poniższym kodzie:

Sub New(ByVal s As String)

Konstruktory są często przeciążone, jak w poniższym kodzie:

Sub New(ByVal s As String, i As Integer)

Podczas definiowania klasy pochodnej z innej klasy pierwszy wiersz konstruktora musi być wywołaniem konstruktora klasy bazowej, chyba że klasa bazowa ma dostępny konstruktor, który nie przyjmuje żadnych parametrów. Wywołanie klasy bazowej zawierającej na przykład powyższego konstruktora to MyBase.New(s). W przeciwnym razie jest opcjonalny, MyBase.New a środowisko uruchomieniowe języka Visual Basic wywołuje je niejawnie.

Po zapisaniu kodu w celu wywołania konstruktora obiektu nadrzędnego można dodać do procedury dowolny dodatkowy kod inicjowania Sub New . Sub New może akceptować argumenty, gdy są wywoływane jako konstruktor sparametryzowany. Te parametry są przekazywane z procedury wywołującej konstruktor, na przykład Dim AnObject As New ThisClass(X).

Finalizowanie podrzędne

Przed zwolnieniem obiektów clR automatycznie wywołuje metodę Finalize dla obiektów, które definiują procedurę Sub Finalize . Metoda Finalize może zawierać kod, który musi zostać wykonany tuż przed zniszczeniem obiektu, na przykład kod do zamykania plików i zapisywania informacji o stanie. Istnieje niewielka kara za wykonanie Sub Finalizeoperacji , dlatego należy zdefiniować metodę Sub Finalize tylko wtedy, gdy trzeba jawnie zwolnić obiekty.

Uwaga

Moduł odśmiecanie pamięci w clR nie (i nie może) usuwać niezarządzanych obiektów, obiektów wykonywanych bezpośrednio przez system operacyjny poza środowiskiem CLR. Dzieje się tak, ponieważ różne niezarządzane obiekty muszą być usuwane na różne sposoby. Te informacje nie są bezpośrednio skojarzone z niezarządzanymi obiektami; Należy go znaleźć w dokumentacji obiektu . Klasa, która używa niezarządzanych obiektów, musi usunąć je w swojej Finalize metodzie.

Destruktor to chroniona Finalize metoda, która może być wywoływana tylko z klasy, do których należy, lub z klas pochodnych. System wywołuje Finalize automatycznie, gdy obiekt zostanie zniszczony, dlatego nie należy jawnie wywoływać Finalize z zewnątrz implementacji klasy pochodnej Finalize .

W przeciwieństwie do Class_Terminatemetody , która jest wykonywana natychmiast po ustawieniu obiektu na nic, zwykle występuje opóźnienie między utratą zakresu a wystąpieniem destruktora Finalize w języku Visual Basic. Program Visual Basic .NET umożliwia drugi rodzaj destruktora, IDisposable.Disposektóry można jawnie wywołać w dowolnym momencie, aby natychmiast zwolnić zasoby.

Uwaga

Destruktor Finalize nie powinien zgłaszać wyjątków, ponieważ nie można ich obsłużyć przez aplikację i może spowodować zakończenie działania aplikacji.

Jak działają nowe i finalizować metody w hierarchii klas

Za każdym razem, gdy wystąpienie klasy jest tworzone, środowisko uruchomieniowe języka wspólnego (CLR) próbuje wykonać procedurę o nazwie New, jeśli istnieje w tym obiekcie. New jest typem procedury nazywanej constructor , która służy do inicjowania nowych obiektów przed wykonaniem jakiegokolwiek innego kodu w obiekcie. Konstruktor New może służyć do otwierania plików, nawiązywania połączenia z bazami danych, inicjowania zmiennych i dbania o wszelkie inne zadania, które należy wykonać, zanim będzie można użyć obiektu.

Po utworzeniu Sub New wystąpienia klasy pochodnej konstruktor klasy bazowej wykonuje najpierw, a następnie konstruktory w klasach pochodnych. Dzieje się tak, ponieważ pierwszy wiersz kodu w konstruktorze Sub New używa składni MyBase.New()do wywoływania konstruktora klasy bezpośrednio powyżej samej w hierarchii klas. Sub New Konstruktor jest następnie wywoływany dla każdej klasy w hierarchii klas do momentu osiągnięcia konstruktora dla klasy bazowej. W tym momencie kod w konstruktorze dla klasy bazowej jest wykonywany, a następnie kod w każdym konstruktorze we wszystkich klasach pochodnych, a kod w najbardziej pochodnych klasach jest wykonywany ostatnio.

Screenshot showing class hierarchy constructors and inheritance.

Gdy obiekt nie jest już potrzebny, clR wywołuje metodę Finalize dla tego obiektu przed zwolnieniem pamięci. Metoda Finalize jest wywoływana destructor , ponieważ wykonuje zadania oczyszczania, takie jak zapisywanie informacji o stanie, zamykanie plików i połączeń z bazami danych oraz inne zadania, które należy wykonać przed zwolnieniem obiektu.

Screenshot showing the Finalize method destructor.

IDisposable, interfejs

Wystąpienia klas często kontrolują zasoby, które nie są zarządzane przez clR, takie jak obsługa systemu Windows i połączenia bazy danych. Te zasoby muszą zostać usunięte w Finalize metodzie klasy, tak aby były zwalniane, gdy obiekt zostanie zniszczony przez moduł odśmiecenia pamięci. Jednak moduł odśmieceń pamięci niszczy obiekty tylko wtedy, gdy clR wymaga więcej wolnej pamięci. Oznacza to, że zasoby mogą nie być zwalniane, dopóki obiekt nie przekroczy zakresu.

Aby uzupełnić odzyskiwanie pamięci, klasy mogą zapewnić mechanizm aktywnego zarządzania zasobami systemowymi, jeśli implementują IDisposable interfejs. IDisposable ma jedną metodę , Disposektórą klienci powinni wywołać po zakończeniu korzystania z obiektu. Możesz użyć Dispose metody , aby natychmiast zwolnić zasoby i wykonywać zadania, takie jak zamykanie plików i połączeń bazy danych. W przeciwieństwie do destruktora Finalize metoda nie jest wywoływana Dispose automatycznie. Klienci klasy muszą jawnie wywoływać Dispose , gdy chcesz natychmiast zwolnić zasoby.

Implementowanie interfejsu IDisposable

Klasa, która implementuje IDisposable interfejs, powinna zawierać następujące sekcje kodu:

  • Pole do śledzenia, czy obiekt został usunięty:

    Protected disposed As Boolean = False
    
  • Przeciążenie Dispose klasy zwalnia zasoby. Ta metoda powinna być wywoływana przez Dispose metody i Finalize klasy bazowej:

    Protected Overridable Sub Dispose(ByVal disposing As Boolean)
        If Not Me.disposed Then
            If disposing Then
                ' Insert code to free managed resources.
            End If
            ' Insert code to free unmanaged resources.
        End If
        Me.disposed = True
    End Sub
    
  • Implementacja tej funkcji Dispose zawiera tylko następujący kod:

    Public Sub Dispose() Implements IDisposable.Dispose
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub
    
  • Zastąpienie Finalize metody zawierającej tylko następujący kod:

    Protected Overrides Sub Finalize()
        Dispose(False)
        MyBase.Finalize()
    End Sub
    

Wyprowadzanie z klasy implementujące funkcję IDisposable

Klasa, która pochodzi z klasy bazowej, która implementuje IDisposable interfejs, nie musi zastępować żadnej z metod podstawowych, chyba że używa dodatkowych zasobów, które należy usunąć. W takiej sytuacji klasa pochodna powinna zastąpić metodę klasy bazowej, aby usunąć zasoby klasy Dispose(disposing) pochodnej. To zastąpienie musi wywołać metodę klasy bazowej Dispose(disposing) .

Protected Overrides Sub Dispose(ByVal disposing As Boolean)
    If Not Me.disposed Then
        If disposing Then
            ' Insert code to free managed resources.
        End If
        ' Insert code to free unmanaged resources.
    End If
    MyBase.Dispose(disposing)
End Sub

Klasa pochodna nie powinna zastępować metod i Finalize klas Dispose bazowych. Gdy metody te są wywoływane z wystąpienia klasy pochodnej, implementacja klasy bazowej tych metod wywołuje przesłonięcia klasy pochodnej Dispose(disposing) metody.

Odzyskiwanie pamięci i finalizowanie destruktora

Program .NET Framework używa systemu odzyskiwania pamięci śledzenia odwołań do okresowego wydawania nieużywanych zasobów. W programie Visual Basic 6.0 i starszych wersjach użyto innego systemu o nazwie zliczanie odwołań do zarządzania zasobami . Chociaż oba systemy wykonują tę samą funkcję automatycznie, istnieje kilka ważnych różnic.

ClR okresowo niszczy obiekty, gdy system określa, że takie obiekty nie są już potrzebne. Obiekty są zwalniane szybciej, gdy zasoby systemowe są w krótkim czasie, a rzadziej w przeciwnym razie. Opóźnienie między utratą zakresu a wydaniem środowiska CLR oznacza, że w przeciwieństwie do obiektów w języku Visual Basic 6.0 i wcześniejszych wersjach, nie można określić dokładnie, kiedy obiekt zostanie zniszczony. W takiej sytuacji mówi się, że obiekty mają niedeterministyczny okres istnienia. W większości przypadków okres istnienia niedeterministyczny nie zmienia sposobu pisania aplikacji, o ile pamiętasz, że Finalize destruktor może nie być wykonywany natychmiast, gdy obiekt utraci zakres.

Kolejna różnica między systemami odzyskiwania pamięci obejmuje użycie elementu Nothing. Aby skorzystać z zliczania odwołań w visual Basic 6.0 i starszych wersjach, programiści czasami przypisani Nothing do zmiennych obiektów w celu wydania odwołań do przechowywanych zmiennych. Jeśli zmienna przechowywała ostatnie odwołanie do obiektu, zasoby obiektu zostały natychmiast zwolnione. W nowszych wersjach języka Visual Basic, chociaż mogą występować przypadki, w których ta procedura jest nadal cenna, wykonanie tej procedury nigdy nie powoduje natychmiastowego zwolnienia odwołanego obiektu. Aby natychmiast zwolnić zasoby, użyj metody obiektu Dispose , jeśli jest dostępna. Jedynym czasem, w którym należy ustawić zmienną Nothing , jest czas, w którym jego okres istnienia jest długi w stosunku do czasu, w którym moduł odśmiecenia pamięci będzie wykrywał oddzielone obiekty.

Zobacz też