marcoborn
Goto Top

Richtiges Löschen globaler Variablen in VB.NET

Hallo Forum,
ich habe ein Verständnisproblem, wie man Variablen richtig wieder löscht. Folgendes Beispiel.

Ich habe ein Programm, das aus 2 Klassen besteht, einer Hauptklasse und einer Unterklasse. In der Hauptklasse definiere ich eine globale Variable, die auf das Interface der Unterklasse verweist, so dass ich die Funktionen der Unterklasse dort nutzen kann. Wie kann ich aber bei Programmende diese Variablen wieder richtig löschen, damit der Speicher wieder freigegeben wird?

Kann mir bitte jemand ein kurzes Beispiel hierfür zeigen?


Vielen Dank,
M. Born

Content-ID: 360722

Url: https://administrator.de/contentid/360722

Ausgedruckt am: 21.11.2024 um 21:11 Uhr

colinardo
colinardo 11.01.2018 aktualisiert um 14:48:08 Uhr
Goto Top
Servus M.Born.
Da gibt's verschiedene Möglichkeiten, die gängigste ist die Nutzung des Using-Statements
Using obj as new Subclass 
    ' hier ist die Variable "obj" gültig  
End Using
' ab hier existiert sie nicht mehr  
Im Allgemeinen wird der Speicher einer Variablen aber automatisch wieder freigegeben wenn sei Out of Scope Ist und sie nicht mehr benötigt wird. Die Garbage Collection sorgt regelmäßig dafür.
Manuell können Objekte über ihre Dispose() Methode freigegeben werden sofern das Interface dafür implementiert ist, für das Using ist ebenfalls IDisposable zu implementieren.
Detailliertere Info dazu
https://docs.microsoft.com/en-us/dotnet/visual-basic/programming-guide/l ...

Grüße Uwe
emeriks
emeriks 11.01.2018 um 14:02:44 Uhr
Goto Top
Hi,
ja, entweder mit "Using". Das setzt "Disposable Support" in den Klassen voraus. ("Implements IDisposable")

Aber:
Wenn Du da keine API mit Declare aufrufst, dann wird beim Programmende (Prozessende) eines VB.Net-Programms eh aller Speicher geleert.

E.
MarcoBorn
MarcoBorn 11.01.2018 um 14:12:21 Uhr
Goto Top
Hallo Uwe,
vielen Dank für die schnelle Antwort.

Das mit dem Using hatte ich an einigen Stellen auch schon eingesetzt. Bei einer globalen Variable erhalte ich aber den Hinweis, dass die Verwendung außerhalb einer Variable nicht zulässig ist.
Verwende ich Using innerhalb von Methoden erhalte ich in einigen Fällen die Meldung, dass die Subklasse System.IDisposable implementieren muss.

In dem Programming-Guide aus Deinem Link wird wieder auf die Dispose-Funktionen verwiesen. Mir ist nur nicht ganz klar, wo die genau hingehören, in die Haupt- oder Subklasse und wie ich dann dem GC mitteile, dass die Subklasse nicht mehr benötigt wird. Gibt es irgendwo im Netz ein Tutorial, wo an einem einfachen Beispiel der Einsatz von Dispose und Finalize etc. dargestellt wird?

Viele Grüße,
M. Born
emeriks
emeriks 11.01.2018 aktualisiert um 14:35:18 Uhr
Goto Top
Jene Klasse, deren Instanz Du mit "Using" eingrenzt, muss die Schnittstelle "IDisposable" implementieren.

Class Test1
End Class

füge einfach hinzu "Implements IDisposable" <Enter>
Nach dem Enter fügt er Dir am Ende der Klasse einen Block mit notwendigen Member hinzu.
Public Class Test1
  Implements IDisposable

#Region "IDisposable Support" 
  Private disposedValue As Boolean ' So ermitteln Sie überflüssige Aufrufe  

  ' IDisposable  
  Protected Overridable Sub Dispose(disposing As Boolean)
    If Not Me.disposedValue Then
      If disposing Then
        ' TODO: Verwalteten Zustand löschen (verwaltete Objekte).  
      End If

      ' TODO: Nicht verwaltete Ressourcen (nicht verwaltete Objekte) freigeben und Finalize() unten überschreiben.  
      ' TODO: Große Felder auf NULL festlegen.  
    End If
    Me.disposedValue = True
  End Sub

  ' TODO: Finalize() nur überschreiben, wenn Dispose(ByVal disposing As Boolean) oben über Code zum Freigeben von nicht verwalteten Ressourcen verfügt.  
  'Protected Overrides Sub Finalize()  
  '    ' Ändern Sie diesen Code nicht. Fügen Sie oben in Dispose(ByVal disposing As Boolean) Bereinigungscode ein.  
  '    Dispose(False)  
  '    MyBase.Finalize()  
  'End Sub  

  ' Dieser Code wird von Visual Basic hinzugefügt, um das Dispose-Muster richtig zu implementieren.  
  Public Sub Dispose() Implements IDisposable.Dispose
    ' Ändern Sie diesen Code nicht. Fügen Sie oben in Dispose(disposing As Boolean) Bereinigungscode ein.  
    Dispose(True)
    GC.SuppressFinalize(Me)
  End Sub
#End Region

End Class
emeriks
emeriks 11.01.2018 aktualisiert um 14:34:37 Uhr
Goto Top
Wenn Du jetzt

Using X as Test1
  ....
End Using

anwendest, dann wir beim Verlassen des Using-Blocks für X (Instanz von Test1) automatisch die Methode "Dispose" ausgeführt.

Wenn Du jetzt in Klasse "Test1" z.B. eine List(of String) hast, dann kannst Du in der Methode "Dispose" diese Liste explizit leeren lassen.
(Zeile 4 - 10)
(Zeile 21)

Public Class Test1
  Implements IDisposable

  Private MyList as new List(of String)

  Public Sub New()
     For I as Integer = 1 to 1000
        MyList.Add(I)
     End
  End Sub

#Region "IDisposable Support" 
  Private disposedValue As Boolean ' So ermitteln Sie überflüssige Aufrufe  

  ' IDisposable  
  Protected Overridable Sub Dispose(disposing As Boolean)
    If Not Me.disposedValue Then
      If disposing Then
        ' TODO: Verwalteten Zustand löschen (verwaltete Objekte).  

        MyList.Clear

      End If

      ' TODO: Nicht verwaltete Ressourcen (nicht verwaltete Objekte) freigeben und Finalize() unten überschreiben.  
      ' TODO: Große Felder auf NULL festlegen.  
    End If
    Me.disposedValue = True
  End Sub

  ' TODO: Finalize() nur überschreiben, wenn Dispose(ByVal disposing As Boolean) oben über Code zum Freigeben von nicht verwalteten Ressourcen verfügt.  
  'Protected Overrides Sub Finalize()  
  '    ' Ändern Sie diesen Code nicht. Fügen Sie oben in Dispose(ByVal disposing As Boolean) Bereinigungscode ein.  
  '    Dispose(False)  
  '    MyBase.Finalize()  
  'End Sub  

  ' Dieser Code wird von Visual Basic hinzugefügt, um das Dispose-Muster richtig zu implementieren.  
  Public Sub Dispose() Implements IDisposable.Dispose
    ' Ändern Sie diesen Code nicht. Fügen Sie oben in Dispose(disposing As Boolean) Bereinigungscode ein.  
    Dispose(True)
    GC.SuppressFinalize(Me)
  End Sub
#End Region
End Class
MarcoBorn
MarcoBorn 11.01.2018 um 14:48:54 Uhr
Goto Top
Hallo,
Dir auch vielen Dank für die Hilfe. Ich habe Deine Vorgehensweise versucht, in meinem Programm umzusetzen. Hier der Code aus meiner Haupt-Klasse:
Private Sub mPrüfung()
  Using mStatusfenster As IStatusfenster = New ClsStatusfensterklasse
    mStatusfenster.Show()
  End Using
End Sub

In der Sub-Klasse habe ich jetzt folgenden Code:
Friend Interface IStatusfenster
  'weitere Funktionen  
  Sub Dispose()
End Interface

Friend Class ClsMboStatusfensterklasse
  Implements IStatusfenster, IDisposable

#Region "IDisposable Support" 
'Die 3 automatisch erstellten Funktionen für Dispose und Finalize  
#End Region

Ich erhalte jetzt aber weiterhin die Fehlermeldung "Ein Using-Operand vom Typ "IStatusfenster" muss System.IDisposable implementieren." Nutze ich stattdessen Dim, funktioniert der Code. Woran kann das liegen?

Viele Grüße,
M. Born
emeriks
emeriks 11.01.2018 aktualisiert um 15:03:09 Uhr
Goto Top
Wozu das "IStatusfenster" ?

Using mStatusfenster As New ClsMboStatusfensterklasse 
....

Friend Class ClsMboStatusfensterklasse 
  Implements IDisposable 
.....
MarcoBorn
MarcoBorn 11.01.2018 um 15:14:04 Uhr
Goto Top
Das liegt daran, dass ich in der Statusfensterklasse private Methoden habe, die ich über das Interface bereitstelle. Lösche ich es aus der Implements-Anweisung raus, bekomme ich die Meldung "Die Schnittstelle IStatusfenster wird nicht von dieser Klasse implementiert."
emeriks
Lösung emeriks 11.01.2018 aktualisiert um 15:38:58 Uhr
Goto Top
Ich kann nicht ganz folgen, kenne Dein Klassen-Design nicht.

Im "IStatusfenster" muss der Member "Dispose" raus. Soviel ist klar.
Und die "ClsMboStatusfensterklasse" kann ja "IStatusfenster" implementieren.
(Überhaupt: "ClsMboStatusfensterklasse" vs. "....= New ClsStatusfensterklasse" --- Schreibfehler?)

Beim "Using" darfst Du aber nicht auf die Schnettstelle "IStatusfenster" einschränken, weil diese nicht "IDisposable" implementiert.
Wenn doch notwendig dann so
  Using mStatusfenster As New ClsMboStatusfensterklasse 
     dim xStatusfenster as IStatusfenster = DirectCast(mStatusfenster,IStatusfenster)

    .... mit xStatusfenster weiterarbeiten
   xStatusfenster.Methode_XYZ_von_IStatusfenster()
   
    ... oder ....

   With DirectCast(mStatusfenster,IStatusfenster)
      .Methode_XYZ_von_IStatusfenster() 
   End With
  End  Using
MarcoBorn
MarcoBorn 11.01.2018 um 16:11:12 Uhr
Goto Top
Das Dispose habe ich jetzt aus dem IStatusfenster entfernt.

Nachdem ich auch den Umweg über DirectCast nutze, funktioniert auch die Using-Anweisung. Ich werde jetzt alle Klassen meines Programms so umstellen.

Vielen Dank,
M. Born