ProgrammationDéveloppeur VB.NET

Comment implémenter des constructeurs (Sub New) et des destructeurs (Finalize/Dispose) en Visual Basic, quand appliquer quelles méthodes et quelles sont les particularités de leur appel ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse.

En Visual Basic, un constructeur est une procédure Sub New, qui est appelée lors de la création d'une instance d'une classe et initialise l'objet. Un destructeur est implémenté à l'aide de la méthode Finalize ou de l'interface IDisposable (méthode Dispose), ce qui est particulièrement important pour libérer des ressources.

Dans le Visual Basic classique, le constructeur était appelé automatiquement lors de la création d'objets (Class_Initialize), le destructeur – lors de la suppression (Class_Terminate). Dans VB.NET, des constructeurs surchargés ont été ajoutés, délimitant la libération des ressources gérées et non gérées, et l'utilisation du ramasse-miettes (GC).

Problème

Une utilisation incorrecte des constructeurs ou des destructeurs conduit à des fuites de mémoire, à une mauvaise initialisation des objets ou à des blocages de ressources (par exemple, des fichiers).

Solution

Utilisez Sub New pour initialiser des objets, implémentez toujours Dispose pour libérer explicitement des ressources. Si un destructeur (Finalize) est utilisé, gardez à l'esprit la latence du GC et l'impossibilité de prévoir le moment de son appel.

Exemple de code :

Public Class ResourceHolder Implements IDisposable Private resource As SomeResource Public Sub New() resource = New SomeResource() Console.WriteLine("Ressource allouée") End Sub Protected Overrides Sub Finalize() Dispose(False) MyBase.Finalize() End Sub Public Sub Dispose() Implements IDisposable.Dispose Dispose(True) GC.SuppressFinalize(Me) End Sub Protected Overridable Sub Dispose(disposing As Boolean) If disposing Then If resource IsNot Nothing Then resource.Release() resource = Nothing End If End If End Sub End Class

Caractéristiques clés :

  • Sub New est toujours appelé lors de la création d'un objet (New)
  • Dispose sert à libérer explicitement des ressources (par exemple, des fichiers), tandis que Finalize protège contre les fuites lors de la libération implicite
  • Appelez toujours GC.SuppressFinalize(this) à l'intérieur de Dispose pour éviter un double nettoyage

Questions pièges.

Peut-on appeler manuellement le constructeur Sub New d'un objet déjà existant ?

Non, le constructeur est appelé seulement lors de la création d'un objet. Pour réinitialiser, utilisez une méthode distincte Reset ou similaire.

Quand Finalize est-il appelé et est-il toujours garanti ?

Finalize est appelé par le ramasse-miettes lors de la destruction de l'objet, mais son exécution n'est pas garantie (par exemple, en cas de terminaison anormale du processus ou de coupure de courant).

Pourquoi faut-il appeler GC.SuppressFinalize à l'intérieur de Dispose ?

Cela empêche l'appel répété de Finalize pour un objet déjà libéré manuellement, améliorant les performances et évitant les fuites de mémoire.

Erreurs typiques et anti-modèles

  • Non libération des ressources non gérées (par exemple, des descripteurs de fichiers)
  • Appel direct de Finalize (ce qui est inacceptable — il n'est appelé que par le ramasse-miettes)
  • Absence de GC.SuppressFinalize dans Dispose

Exemple de la vie réelle

Cas négatif

Dans le projet, Dispose n'a pas été implémenté, et plusieurs fichiers restaient bloqués après la fin de l'application - les ressources n'étaient pas libérées jusqu'à ce que le ramasse-miettes n'intervienne.

Avantages :

  • Moins de code

Inconvénients :

  • Fuites de ressources
  • Pannes lors du redémarrage du programme

Cas positif

Implémentation d'IDisposable et de Dispose, utilisation de Using lors du travail avec des ressources externes. Tous les fichiers se ferment correctement et l'application fonctionne de manière stable.

Avantages :

  • Pas de fuites
  • Fiabilité accrue

Inconvénients :

  • Nécessite de la discipline lors du codage