Dupliquer possible:
Comment dit-on si une référence d'objet amovible est supprimée?
Existe-t-il une méthode pour vérifier si l'objet a été éliminé différemment alors
try
{
myObj.CallRandomMethod();
} catch (ObjectDisposedException e)
{
// now I know object has been disposed
}
Dans mon cas, j'utilise la classe TcpClient
qui a la méthode Close()
qui dispose un objet et cela peut se produire dans un morceau de code que je n'ai pas le contrôle Dans ce cas, j'aimerais avoir une meilleure solution que d'attraper l'exception.
Un bon moyen consiste à dériver de TcpClient et à annuler la méthode de mise au rebut (bool):
class MyClient : TcpClient {
public bool IsDead { get; set; }
protected override void Dispose(bool disposing) {
IsDead = true;
base.Dispose(disposing);
}
}
Ce qui ne fonctionnera pas si l'autre code a créé l'instance. Vous devrez ensuite faire quelque chose de désespéré, comme utiliser Reflection pour obtenir la valeur du membre privé m_CleanedUp. Ou attraper l'exception.
Franchement, aucun n’est susceptible de très bien se terminer. Vous voulez vraiment faire écrire sur le port TCP. Mais vous ne le ferez pas, ce code buggy que vous ne pouvez pas contrôler est maintenant en contrôle de votre code. Vous avez augmenté l'impact du bogue. Parler au propriétaire de ce code et résoudre quelque chose est de loin la meilleure solution.
EDIT: Un exemple de réflexion:
using System.Reflection;
public static bool SocketIsDisposed(Socket s)
{
BindingFlags bfIsDisposed = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetProperty;
// Retrieve a FieldInfo instance corresponding to the field
PropertyInfo field = s.GetType().GetProperty("CleanedUp", bfIsDisposed);
// Retrieve the value of the field, and cast as necessary
return (bool)field.GetValue(s, null);
}
La solution fiable attrape l'exception ObjectDisposedException.
La solution pour écrire votre implémentation substituée de la méthode Dispose ne fonctionne pas, car il existe une condition de concurrence entre le thread qui appelle la méthode Dispose et celle accédant à l'objet: après avoir vérifié la propriété hypothétique IsDisposed, l'objet pourrait être réellement supprimé. , jetant l’exception tout de même.
Une autre approche pourrait consister à exposer un événement hypothétique Disposed (comme this ), utilisé pour notifier l’objet éliminant à chaque objet intéressé, mais cela pourrait être difficile à planifier en fonction de la conception du logiciel.
Si vous ne savez pas si l'objet a été supprimé ou non, vous devez appeler la méthode Dispose
elle-même plutôt que des méthodes telles que Close
. Bien que le framework ne garantisse pas que la méthode Dispose doit être exécutée sans exception, même si l'objet avait déjà été supprimé, il s'agit d'un modèle commun et, à ma connaissance, implémenté sur tous les objets à jeter du framework.
Le modèle typique pour Dispose
, selon Microsoft :
public void Dispose()
{
Dispose(true);
// Use SupressFinalize in case a subclass
// of this type implements a finalizer.
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
// If you need thread safety, use a lock around these
// operations, as well as in your methods that use the resource.
if (!_disposed)
{
if (disposing) {
if (_resource != null)
_resource.Dispose();
Console.WriteLine("Object disposed.");
}
// Indicate that the instance has been disposed.
_resource = null;
_disposed = true;
}
}
Notez la vérification sur _disposed
. Si vous appelez une méthode Dispose
implémentant ce modèle, vous pouvez appeler Dispose autant de fois que vous le souhaitez sans toucher aux exceptions.
La meilleure pratique consiste à le mettre en œuvre vous-même à l'aide d'un champ booléen local: http://www.niedermann.dk/2009/06/18/BestPracticeDisposePatternC.aspx