Je travaille sur une classe qui traite de nombreux objets SQL - Connexion, DataDapter, CommandBuilder, etc. Il existe plusieurs instances où nous avons un code comme celui-ci:
private void DisposeObject<TDisposable>( ref TDisposable disposableObject ) where TDisposable : class, IDisposable { if( disposableObject != null ) { disposableObject.Dispose(); disposableObject = null; } }
10 Réponses :
Vous devez implémenter C'est pas nécessaire pour définir des variables sur Idisposable code> dans la classe qui possède ces champs. Voir Mon article de blog sur le sujet. Si cela ne fonctionne pas bien, la classe ne suit pas les principes de l'OOP et doit être refacturé. P>
null code> après les disposition. p>
Je ne suis pas en mesure d'utiliser le en utilisant la déclaration code> pour la plupart de mes cas. J'ai mis à jour ma question.
Vous devez considérer si vous pouvez utiliser le à l'aide de code> instruction.
Cannot assign to 'c' because it is a 'using variable'
Cela suppose bien sûr que la durée de vie de la ressource est une seule méthode appelée, ce qui est peu probable dans ce cas, comme indiqué par la nécessité de vérifier les varaibles pour NULL en premier.
@James, vous êtes absolument correct. @Mark, j'ai mis à jour ma question.
Pourquoi n'utilisez-vous pas l'utilisation de C # construire? http://msdn.microsoft.com/en-us/library/yh598w02. Aspx Réglage sur null si non requis. P>
D'autres ont recommandé le en utilisant code> construction, que je recommande également. Cependant, j'aimerais souligner que, même si vous avez besoin d'une méthode utilitaire, il est totalement inutile de le rendre générique de la manière dont vous avez fait. Déclarez simplement votre méthode pour prendre un
Idisposable code>:
J'ai essayé cela, mais pour une raison quelconque, je devais jeter tous mes appels à la méthode. Je conviens que cela devrait fonctionner! Je vais devoir vérifier.
@Jerod: L'emballage ne fonctionnera pas, car vous modifiez la valeur de jetable code> au lieu de
mTransaction code>. @ JS: Étant donné que nous allons être modifiant i> jetableObject, le compilateur doit connaître le type exact.
@Jerod - Les paramètres de la méthode ne sont pas autorisés à être covariant dans ce cas en raison du mot clé ref code>, sinon, vous pouvez passer dans un
sqlconnection code>, puis définissez l'objet sur un instance de
filtream code> de la méthode (qui enfreindrait la sécurité de type de l'argument)
@James, @john. Très bons points! Je savais qu'il y avait probablement une raison pour laquelle il n'était pas autorisé. Il est bon de savoir pourquoi j'étais «forcé» d'aller générique au lieu d'utiliser l'interface commune.
@John: Une meilleure explication mieux que la mienne (j'ai continué à penser »mais la définition à NULL devrait être ok" - je n'ai pas envisagé de la définir à un type complètement différent)
Je suppose que ce sont des champs et non des variables locales, pourquoi le mot clé code> n'a pas de sens. p>
est cette fonction générique une mauvaise idée? p> blockQuote>
Je pense que c'est une bonne idée et j'ai utilisé une fonction similaire plusieurs fois; +1 pour le rendre générique. P>
est-il nécessaire de définir l'objet sur NULL? P> blockQuote>
Techniquement, un objet doit permettre à plusieurs appels à son
Disposer la méthode code>. (Par exemple, cela se produit si un objet est ressuscité lors de la finalisation.) En pratique, c'est à vous de faire confiance aux auteurs de ces classes ou si vous souhaitez coder de manière défensive. Personnellement, je vérifie NULL, puis définissez des références à NULL ensuite. P>
EDIT: strong> Si ce code est à l'intérieur de votre propre objet Dispose de la méthode code>, puis de définir les références à Null ne résoudra pas la mémoire. Au lieu de cela, il est pratique comme une défense contre la double élimination. P>
Je vais supposer que vous créez la ressource dans une méthode, en l'éliminant dans une autre, et utilisez-la dans un ou plusieurs autres, rendant le Dans ce cas, votre méthode est parfaitement bien. P>
Aussi loin la deuxième partie de votre question (", le réglage à NULL est nécessaire?"), la réponse simple est "non, mais ça ne fait rien". P>
La plupart des objets contiennent une ressource - la mémoire, que la collection à la poubelle traite de la liberté, de sorte que nous n'avons pas à vous en soucier. Certaines détiennent également une autre ressource: une poignée de fichier, une connexion de base de données, etc. Pour la deuxième catégorie, nous devons mettre en œuvre Idisposable, libérer cette autre ressource. p>
Une fois la méthode Disposition appelée, les deux catégories parce que la même chose: ils tiennent la mémoire. Dans ce cas, nous pouvons simplement laisser la variable sortir de la portée, laisser tomber la référence à la mémoire et permettre à GC de libérer éventuellement - ou nous pouvons forcer la question, en définissant la variable à NULL, et en laissant explicitement abandonner la référence à la mémoire. Nous devons encore attendre que le GC frappe pour que la mémoire soit réellement libérée, et plus que probablement la variable s'éteindra de toute façon, des moments après la définir à NULL, donc dans la grande majorité des cas, il aura Aucun effet du tout, mais dans quelques cas rares, il permettra à la mémoire d'être libérée quelques secondes plus tôt. P>
Cependant, si votre cas spécifique, où vous vérifiez que NULL pour voir si vous devez appeler du tout, vous devriez probablement em> le mettre à la disposition sur NULL, s'il y a une chance que vous puissiez appeler () deux fois. p> en utilisant code> instruction inutile pour vous. p>
Vous n'avez jamais besoin de définir des variables sur I ' m curieux de savoir pourquoi vous pensez que vous ne pouvez pas utiliser le null code>. L'ensemble du point de
Idisposable.Dispose code> est d'obtenir l'objet dans un état dans lequel elle peut accrocher en mémoire de manière inoffensive jusqu'à ce que le GC se termine, de sorte que vous «disposez-vous et oubliez».
à l'aide de la déclaration code>. Création d'un objet dans une méthode et l'élimination dans une méthode différente est un em> strong> odeur de code dans mon livre, car vous perdez bientôt une trace de ce qui est ouvert là où. Mieux vaut refacturer le code comme celui-ci: P>
using(var xxx = whatever()) {
LotsOfProcessing(xxx);
EvenMoreProcessing(xxx);
NowUseItAgain(xxx);
}
Je conviens que ce n'est pas sans odeurs de code. Ce code provient d'une classe de bibliothèque SQL utilisée dans plusieurs produits. La plus grande raison pour laquelle le en utilisant la déclaration code> ne fonctionne pas est dû au fait que l'une des fonctionnalités nécessaires est le support de transaction. L'utilisateur de la bibliothèque nous dit de démarrer la transaction, puis de faire plusieurs manipulations de données, puis nous nous disent de commettre la transaction. Je pense que c'est un cas d'utilisation très raisonnable, car cela crée une séparation entre le code client et le code spécifique SQL.
@Jerod, n'est-il pas possible de créer la connexion, de commencer la transaction, d'appeler toutes les méthodes de la bibliothèque, de valider la transaction et de disposer la connexion, tout en une méthode? Ce que vous décrivez, c'est exactement comment j'ai conçu mes classes de bibliothèque SQL, mais je peux toujours utiliser à l'aide de déclarations code>.
Cela est possible, sauf que l'utilisateur aurait besoin de connaître les détails complexes de notre bibliothèque. Malheureusement, je ne suis pas en liberté de changer notre API publique à ce stade et de travailler avec ce que j'ai eu.
@Jerod, le code d'appel de l'utilisateur contiendrait le à l'aide de la déclaration code>, pas de votre API. Je ne suggérais pas de changer votre API. Peut-être que nous ferions mieux de laisser cette conversation tomber, car je ne vais pas pouvoir dire quelque chose de plus utile à moins que je puisse voir votre API. :-)
Si vos objets ont beaucoup de nettoyage à faire, ils voudront peut-être suivre ce qui doit être supprimé dans une liste séparée de jetables et les gérer tous à la fois. Ensuite, à la dérappement, il n'a pas besoin de se rappeler tout ce qui doit être disposé (ni de vérifier NULL, il regarde simplement la liste).
Cela ne construit probablement pas, mais à des fins d'expanatoires, vous pourrait inclure une recyclebin dans votre classe. Ensuite, la classe doit seulement disposer de la corbeille. P>
public class RecycleBin : IDisposable { private List<IDisposable> _toDispose = new List<IDisposable>(); public void RememberToDispose(IDisposable disposable) { _toDispose.Add(disposable); } public void Dispose() { foreach(var d in _toDispose) d.Dispose(); _toDispose.Clear(); } }
+1 Cela ne fonctionne pas pour ma situation actuelle parce que je ne suis pas tout disposé à la fois. Bien que j'aime cette suggestion et que je puisse devoir l'utiliser à l'avenir.
Étant donné que Idisposable n'inclut aucune façon standard de déterminer si un objet a été éliminé, j'aime mettre des choses à NULL lorsque je les écoute. Assurez-vous que l'élimination d'un objet qui a déjà été disposé est inoffensif, mais il est agréable de pouvoir examiner un objet dans une fenêtre de montre et raconter un coup d'œil que les champs ont été disposés. Il est également agréable de pouvoir avoir un test de code pour vous assurer que les objets qui auraient dû être disposés, sont (en supposant que le code adhère à la convention de nullement de variables lors de leur élimination, et sans autre heure). P>
J'ai répondu à cela dans ma question et répondez ici: P>
Implémentation Idisposable (le modèle jetable) comme Un service (membre de classe) p>
Il a implémenté un composant simpliste et réutilisable qui fonctionne pour tout membre isisposable. P>
Les génériques ne sont pas nécessaires; Le code est beaucoup plus simple sans eux.