2010-10-02 2 views
8

Après avoir lu beaucoup d'articles d'Idisposable, je me suis trompé sur son utilisation. Tous les articles expliquent ce que c'est et comment l'implémenter. Je veux comprendre ce qui nous manquera si nous ne l'avons pas. Il s'agit d'une interface avec une méthode Dispose() en elle. Prenons un exemple Il est souvent indiqué que l'utilisation de disposer dispose d'une connexion de base de données .Écrire notre propre méthode Dispose au lieu d'utiliser Idisposable

Le code serait comme

Public class Test:Idisposable 
{ 
    public Test() 
    { 
    DatabaseConnection databaseConnection = new DatabaseConnection(); 
    } 

    public void Dispose() 
    { 
    if (this.databaseConnection != null) 
    { 
     this.databaseConnection.Dispose(); 
     this.databaseConnection = null; 
    } 
    } 
} 

Bien que Éliminez est mis en oeuvre mais à l'intérieur méthode Éliminez la propriété Éliminez DatabaseConnection est utilisé pour libérer la connexion (this.databaseConnection.Dispose();)

Ma question est pourquoi avons-nous besoin d'implémenter IDisposable dans ce cas? Nous pouvons directement appeler this.databaseConnection.Dispose() et libérer la connexion. Pourquoi implémenter dispose quand il appelle en interne la propriété de disposition de l'objet. Alternative à l'approche de Idisposable nous pouvons implémenter une méthode Libérer pour libérer la mémoire.

Public Class Test 
{ 

public Test() 
{ 
    DatabaseConnection databaseConnection = new DatabaseConnection(); 
} 
public void Release() 
{ 
    if (this.databaseConnection != null) 
    { 
     this.databaseConnection.Dispose(); 
     this.databaseConnection = null; 
    } 

} 
} 

Quelle est la différence entre les deux approches? Avons-nous vraiment besoin d'Idisposable? J'attends avec impatience une explication concrète.

+2

Le code est tout à fait faux, il doit être un membre privé de la classe, et non pas une variable locale du constructeur. –

Répondre

12

Vous avez raison, en utilisant votre méthode Release, vous obtenez exactement le même effet, à condition de toujours vous souvenir de l'appeler.

La raison pour laquelle vous devriez utiliser Dispose/IDisposable pour ce genre de chose est la cohérence. Tous les développeurs .NET connaîtront le modèle IDisposable, et une classe IDisposable indique que vous devez en disposer, et le faire en utilisant la méthode Dispose. En d'autres termes, l'utilisation du modèle IDisposable indique immédiatement à un autre développeur qu'il doit libérer les ressources détenues par la classe, et il doit le faire en appelant la méthode Dispose.

Un autre avantage de la mise en œuvre IDisposable est le bloc à l'aide, qui travaille sur une classe IDisposable:

using(var t = new Test()) 
{ 
    // use t 
} 

En utilisant le code ci-dessus entraînera t être Dispose() ée à la fin du bloc using. C'est du sucre syntaxique pour un bloc try ... finally, mais il tend à rendre ce type de code plus concis et plus facile à lire et à écrire.

+0

indépendamment de la cohérence voyez-vous un autre facteur de motivation à utiliser Idisposable – Piyush

+2

@Piyush - Ne pas permettre au programmeur client d'utiliser un mot-clé dans la langue est plutôt un gros problème qui va bien au-delà de la cohérence. –

+0

Je dirais qu'une partie fondamentale du contrat de l'objet .NET, quels objets devraient essayer d'obéir dans toute la mesure du possible, est que le nettoyage de l'objet avant l'abandon ne nécessite aucune autre action que d'appeler 'IDisposable.Dispose' [pour les classes qui n'implémentent pas 'IDisposable', aucune action ne devrait être requise].Même si 'IDisposable' est une interface, elle devrait être considérée comme faisant partie du contrat' Object', d'autant plus que le fait qu'une classe concrète * n'implémente pas 'IDisposable' soit plus sur la classe que sur le fait que ça faisait*. – supercat

1
  1. Si votre Release() a fonctionné correctement (il ne fait pas, mais qui est une autre affaire), alors les gens devraient apprendre à ce sujet, et d'apprendre quelque chose d'autre avec une autre classe, et ainsi de suite.
  2. Votre Release() n'a jamais pu être trouvé par programme. Il est possible d'appeler par programme Dispose() le cas échéant avec:

    si (obj est IDisposable) ((IDisposable) obj).Disposer();

Bien que ce ne soit pas souvent fait, quand c'est fait, c'est vital.

Il est parfois utile d'avoir une méthode telle que votre Release() si quelqu'un d'autre pourrait vouloir l'appeler pendant l'utilisation de l'objet. Un exemple de ceci est Close() sur Stream. Notez ici cependant que Stream.Dispose() existe toujours et appelle Close().

1

IDisposable vaut la peine d'être implémenté, surtout parce qu'il est idomatique en C#. Tout le monde sait ce que fait IDisposable et comment gérer un objet qui implémente IDisposable. Lorsque vous libérez des ressources en utilisant autre chose que IDisposable.Dispose(), vous déviez de l'idiome généralement compris. Cela signifie qu'un mainteneur n'a pas besoin de connaître les tenants et les aboutissants de votre classe particulière pour éviter les fuites de ressources. Cela peut même être vous, dans 6 mois, lorsque vous avez oublié la plupart de ce que vous avez fait avec ce morceau de code! Tout ce que vous devez savoir, c'est qu'il implémente IDisposable, qui a une signification communément comprise. Rappelez-vous que IDisposable, la plupart du temps, est un signal à un développeur, "Hey, je suis une classe qui contient des références à des ressources non gérées.Vous ne devriez probablement pas attendre sur le garbage collector pour me nettoyer." Notez que ceci peut être indirectement via la composition (une classe qui implémente IDisposable parce qu'elle a des membres privés qui implémentent IDisposable). Lorsqu'un développeur C# décent voit une classe implémentant IDisposable, il doit immédiatement penser "Cet objet est spécial et doit être nettoyé quand j'en ai fini avec". Rien ne vous empêche d'écrire une méthode Release(); Cela signifie simplement que vous avez plus de chances de fuir accidentellement des ressources parce que vous n'utilisez pas le modèle idiomatique.

0

Les objets gérés seront éliminés automatiquement par la récupération de place à un moment non déterministe dans le futur. Cependant, lorsque vous utilisez des objets pouvant contenir des ressources non gérées (qui ne sont pas sous le contrôle du CLR/garbage collection), IDisposable doit être implémenté pour fournir une méthode cohérente et déterministe de renvoi de ces ressources au système d'exploitation.

L'interface n'apporte qu'un réel avantage lorsque l'objet est utilisé dans le contexte d'un bloc using() {...}. Un tel bloc indique au CLR d'appeler la méthode Dispose lorsqu'il frappe l'accolade fermante du bloc. Donc, peu importe ce qui se passe dans ce bloc (à moins d'une défaillance catastrophique du système), votre méthode Dispose est garantie d'être appelée et vos ressources non gérées sont libérées. Par exemple, dans le code que vous avez fourni, si une exception a été levée, votre méthode Release() peut ne jamais avoir été appelée, ce qui peut laisser la connexion ouverte. Cependant, lorsque vous travaillez avec un objet jetable sans un bloc using, lorsque l'exception est levée, le CLR va sauter et appeler votre méthode Dispose avant de lancer l'exception.

1
public class DotNetTips  
{  
private void DoSomeOperation()  
{  
using (SqlConnection con1 = new SqlConnection("First Connection String"), 
      con2 = new SqlConnection(("Second Connection String"))  
{  
// Rest of the code goes here  
}  
} 

private void DoSomeOtherOperation()  
{  
using (SqlConnection con = new SqlConnection("Connection String"))  
using (SqlCommand cmd = new SqlCommand())  
{  
// Rest of the code goes here  
}  
}  
} 
Using statement is useful when we have to call dispose method multiple times on different objects. Otherwise, we will have to call Dispose method on each object as: 


if (con != null) con.Dispose();  
if (cmd != null) cmd.Dispose(); 
+0

Avez-vous une explication de _why_ cela fonctionne? – Ben

Questions connexes