Pour le mécanisme équivalent en C++ (le destructeur), le conseil est le suivant il ne devrait généralement pas lever d'exceptions . Ceci est principalement dû au fait qu'en faisant cela, vous risquez d'interrompre votre processus, ce qui n'est que très rarement une bonne stratégie.
Dans le scénario équivalent en .NET ...
- Une première exception est levée
- Un bloc final est exécuté à la suite de la première exception.
- Le bloc finally appelle une méthode Dispose()
- La méthode Dispose() lève une deuxième exception
... votre processus ne s'arrête pas immédiatement. Cependant, vous perdez des informations car .NET remplace sans hésiter la première exception par la seconde. Un bloc catch situé quelque part en haut de la pile d'appels ne verra donc jamais la première exception. Cependant, on est généralement plus intéressé par la première exception car elle donne de meilleurs indices sur la raison pour laquelle les choses ont commencé à mal tourner.
Étant donné que .NET ne dispose pas d'un mécanisme permettant de détecter si du code est exécuté alors qu'une exception est en suspens, il semble qu'il n'y ait que deux possibilités d'implémentation d'IDisposable :
- Toujours avaler toutes les exceptions qui se produisent à l'intérieur de Dispose(). Ce n'est pas une bonne chose car vous pourriez aussi finir par avaler OutOfMemoryException, ExecutionEngineException, etc. que je préfère généralement laisser détruire le processus lorsqu'elles se produisent sans qu'une autre exception soit déjà en attente.
- Laissez toutes les exceptions se propager hors de Dispose(). Ce n'est pas une bonne chose car vous risquez de perdre des informations sur la cause première du problème, voir ci-dessus.
Alors, quel est le moindre des deux maux ? Y a-t-il une meilleure solution ?
EDIT : Pour clarifier, je ne parle pas de lancer activement les exceptions de Dispose() ou non, je parle de laisser les exceptions lancées par les méthodes appelées par Dispose() se propager hors de Dispose() ou non, par exemple :
using System;
using System.Net.Sockets;
public sealed class NntpClient : IDisposable
{
private TcpClient tcpClient;
public NntpClient(string hostname, int port)
{
this.tcpClient = new TcpClient(hostname, port);
}
public void Dispose()
{
// Should we implement like this or leave away the try-catch?
try
{
this.tcpClient.Close(); // Let's assume that this might throw
}
catch
{
}
}
}