Partager via


Durée de vie des objets : création et destruction d’objets (Visual Basic)

Une instance d’une classe, un objet, est créée à l’aide du New mot clé. Les tâches d’initialisation doivent souvent être effectuées sur de nouveaux objets avant d’être utilisées. Les tâches d’initialisation courantes incluent l’ouverture de fichiers, la connexion aux bases de données et la lecture de valeurs de clés de Registre. Visual Basic contrôle l’initialisation de nouveaux objets à l’aide de procédures appelées constructeurs (méthodes spéciales qui permettent de contrôler l’initialisation).

Une fois qu’un objet quitte l’étendue, il est libéré par le Common Language Runtime (CLR). Visual Basic contrôle la mise en production des ressources système à l’aide de procédures appelées destructeurs. Ensemble, les constructeurs et les destructeurs prennent en charge la création de bibliothèques de classes robustes et prévisibles.

Utilisation de constructeurs et de destructeurs

Les constructeurs et les destructeurs contrôlent la création et la destruction d’objets. Les Sub New procédures et Sub Finalize les procédures de Visual Basic initialisent et détruisent les objets ; ils remplacent les Class_Initialize méthodes utilisées Class_Terminate dans Visual Basic 6.0 et les versions antérieures.

Sous-nouveau

Le Sub New constructeur ne peut s’exécuter qu’une seule fois lorsqu’une classe est créée. Elle ne peut pas être appelée explicitement ailleurs que dans la première ligne de code d’un autre constructeur à partir de la même classe ou d’une classe dérivée. En outre, le code de la Sub New méthode s’exécute toujours avant tout autre code d’une classe. Visual Basic crée implicitement un Sub New constructeur au moment de l’exécution si vous ne définissez pas explicitement une Sub New procédure pour une classe.

Pour créer un constructeur pour une classe, créez une procédure nommée Sub New n’importe où dans la définition de classe. Pour créer un constructeur paramétrable, spécifiez les noms et les types de données des arguments Sub New comme vous le feriez pour spécifier des arguments pour toute autre procédure, comme dans le code suivant :

Sub New(ByVal s As String)

Les constructeurs sont fréquemment surchargés, comme dans le code suivant :

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

Lorsque vous définissez une classe dérivée d’une autre classe, la première ligne d’un constructeur doit être un appel au constructeur de la classe de base, sauf si la classe de base a un constructeur accessible qui ne prend aucun paramètre. Un appel à la classe de base qui contient le constructeur ci-dessus, par exemple, serait MyBase.New(s). Sinon, MyBase.New est facultatif et le runtime Visual Basic l’appelle implicitement.

Après avoir écrit le code pour appeler le constructeur de l’objet parent, vous pouvez ajouter tout code d’initialisation supplémentaire à la Sub New procédure. Sub New peut accepter des arguments lorsqu’ils sont appelés en tant que constructeur paramétrable. Ces paramètres sont transmis à partir de la procédure appelant le constructeur, par exemple Dim AnObject As New ThisClass(X).

Sous-finalisation

Avant de libérer des objets, le CLR appelle automatiquement la Finalize méthode pour les objets qui définissent une Sub Finalize procédure. La Finalize méthode peut contenir du code qui doit s’exécuter juste avant la destruction d’un objet, comme le code de fermeture des fichiers et l’enregistrement des informations d’état. Il existe une légère pénalité de performances pour l’exécution Sub Finalize. Vous devez donc définir une Sub Finalize méthode uniquement lorsque vous devez libérer des objets explicitement.

Remarque

Le garbage collector dans le CLR ne supprime pas (et ne peut pas) supprimer des objets non managés, des objets que le système d’exploitation exécute directement, en dehors de l’environnement CLR. Cela est dû au fait que différents objets non managés doivent être supprimés de différentes manières. Ces informations ne sont pas directement associées à l’objet non managé ; il doit être trouvé dans la documentation de l’objet. Une classe qui utilise des objets non managés doit les supprimer dans sa Finalize méthode.

Le Finalize destructeur est une méthode protégée qui peut être appelée uniquement à partir de la classe à laquelle elle appartient ou des classes dérivées. Le système appelle Finalize automatiquement lorsqu’un objet est détruit. Vous ne devez donc pas appeler Finalize explicitement à partir de l’extérieur de l’implémentation d’une Finalize classe dérivée.

Contrairement Class_Terminateà , qui s’exécute dès qu’un objet est défini sur rien, il existe généralement un délai entre le moment où un objet perd l’étendue et quand Visual Basic appelle le Finalize destructeur. Visual Basic .NET permet un deuxième type de destructeur, IDisposable.Disposequi peut être appelé explicitement à tout moment pour libérer immédiatement des ressources.

Remarque

Un Finalize destructeur ne doit pas lever d’exceptions, car ils ne peuvent pas être gérés par l’application et peuvent entraîner l’arrêt de l’application.

Fonctionnement des méthodes nouvelles et finalises dans une hiérarchie de classes

Chaque fois qu’une instance d’une classe est créée, le Common Language Runtime (CLR) tente d’exécuter une procédure nommée New, s’il existe dans cet objet. New est un type de procédure appelé qui constructor est utilisé pour initialiser de nouveaux objets avant l’exécution d’un autre code dans un objet. Un New constructeur peut être utilisé pour ouvrir des fichiers, se connecter à des bases de données, initialiser des variables et s’occuper des autres tâches qui doivent être effectuées avant qu’un objet puisse être utilisé.

Lorsqu’une instance d’une classe dérivée est créée, le Sub New constructeur de la classe de base s’exécute en premier, suivi de constructeurs dans les classes dérivées. Cela se produit parce que la première ligne de code d’un Sub New constructeur utilise la syntaxe MyBase.New()pour appeler le constructeur de la classe immédiatement au-dessus de lui-même dans la hiérarchie de classes. Le Sub New constructeur est ensuite appelé pour chaque classe de la hiérarchie de classes jusqu’à ce que le constructeur de la classe de base soit atteint. À ce stade, le code dans le constructeur de la classe de base s’exécute, suivi du code de chaque constructeur dans toutes les classes dérivées et le code dans les classes les plus dérivées est exécuté en dernier.

Capture d’écran montrant les constructeurs de hiérarchie de classes et l’héritage.

Lorsqu’un objet n’est plus nécessaire, le CLR appelle la Finalize méthode pour cet objet avant de libérer sa mémoire. La Finalize méthode est appelée car destructor elle effectue des tâches de nettoyage, telles que l’enregistrement des informations d’état, la fermeture des fichiers et des connexions aux bases de données et d’autres tâches qui doivent être effectuées avant de libérer l’objet.

Capture d’écran montrant le destructeur de méthode Finalise.

IDisposable, interface

Les instances de classe contrôlent souvent les ressources non gérées par le CLR, telles que les handles Windows et les connexions de base de données. Ces ressources doivent être supprimées dans la Finalize méthode de la classe, afin qu’elles soient libérées lorsque l’objet est détruit par le garbage collector. Toutefois, le garbage collector détruit les objets uniquement lorsque le CLR nécessite une mémoire plus libre. Cela signifie que les ressources peuvent ne pas être libérées tant que l’objet n’est plus étendu.

Pour compléter le garbage collection, vos classes peuvent fournir un mécanisme permettant de gérer activement les ressources système si elles implémentent l’interface IDisposable . IDisposable a une méthode, Disposeque les clients doivent appeler lorsqu’ils terminent l’utilisation d’un objet. Vous pouvez utiliser la Dispose méthode pour libérer immédiatement des ressources et effectuer des tâches telles que la fermeture des fichiers et des connexions de base de données. Contrairement au Finalize destructeur, la Dispose méthode n’est pas appelée automatiquement. Les clients d’une classe doivent appeler Dispose explicitement lorsque vous souhaitez libérer immédiatement des ressources.

Implémentation d’IDisposable

Une classe qui implémente l’interface IDisposable doit inclure ces sections de code :

  • Champ permettant de suivre si l’objet a été supprimé :

    Protected disposed As Boolean = False
    
  • Surcharge des Dispose ressources de la classe. Cette méthode doit être appelée par les Dispose méthodes de Finalize la classe de base :

    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
    
  • Une implémentation de Dispose ce code contient uniquement le code suivant :

    Public Sub Dispose() Implements IDisposable.Dispose
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub
    
  • Remplacement de la Finalize méthode qui contient uniquement le code suivant :

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

Dérivation d’une classe qui implémente IDisposable

Une classe qui dérive d’une classe de base qui implémente l’interface IDisposable n’a pas besoin de remplacer les méthodes de base, sauf si elle utilise des ressources supplémentaires qui doivent être supprimées. Dans ce cas, la classe dérivée doit remplacer la méthode de la classe de Dispose(disposing) base pour supprimer les ressources de la classe dérivée. Ce remplacement doit appeler la méthode de la classe de Dispose(disposing) base.

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

Une classe dérivée ne doit pas remplacer les méthodes et Finalize les méthodes de la classe de Dispose base. Lorsque ces méthodes sont appelées à partir d’une instance de la classe dérivée, l’implémentation de la classe de base de ces méthodes appelle le remplacement de la classe dérivée de la Dispose(disposing) méthode.

Garbage Collection et finalisez le destructeur

Le .NET Framework utilise le système de garbage collection de suivi des références pour libérer régulièrement des ressources inutilisées. Visual Basic 6.0 et versions antérieures utilisaient un autre système appelé comptage de références pour gérer les ressources. Bien que les deux systèmes effectuent automatiquement la même fonction, il existe quelques différences importantes.

Le CLR détruit périodiquement les objets lorsque le système détermine que ces objets ne sont plus nécessaires. Les objets sont libérés plus rapidement lorsque les ressources système sont en courte disponibilité, et moins fréquemment sinon. Le délai entre le moment où un objet perd de l’étendue et lorsque le CLR libère cela signifie que, contrairement aux objets dans Visual Basic 6.0 et versions antérieures, vous ne pouvez pas déterminer exactement quand l’objet sera détruit. Dans une telle situation, les objets sont dits avoir une durée de vie non déterministe. Dans la plupart des cas, la durée de vie non déterministe ne change pas la façon dont vous écrivez des applications, tant que vous n’oubliez pas que le Finalize destructeur peut ne pas s’exécuter immédiatement lorsqu’un objet perd l’étendue.

Une autre différence entre les systèmes de garbage-collection implique l’utilisation de Nothing. Pour tirer parti du comptage de références dans Visual Basic 6.0 et versions antérieures, les programmeurs sont parfois affectés Nothing aux variables d’objet pour libérer les références contenues dans ces variables. Si la variable contenait la dernière référence à l’objet, les ressources de l’objet ont été libérées immédiatement. Dans les versions ultérieures de Visual Basic, même s’il peut y avoir des cas dans lesquels cette procédure est toujours précieuse, l’exécution n’entraîne jamais la libération immédiate de ses ressources par l’objet référencé. Pour libérer immédiatement des ressources, utilisez la méthode de l’objet Dispose , le cas échéant. La seule fois où vous devez définir une variable Nothing est quand sa durée de vie est longue par rapport au temps nécessaire au garbage collector pour détecter les objets orphelins.

Voir aussi