Для эквивалентного механизма в С++ (деструктор) совет состоит в том, что он обычно не должен исключать какие-либо исключения. Это происходит главным образом из-за того, что вы можете прекратить свой процесс, что очень редко является хорошей стратегией.
В эквивалентном сценарии в .NET...
- Вызывается первое исключение
- Блок finally выполняется в результате первого исключения
- Блок finally вызывает метод Dispose()
- Метод Dispose() генерирует второе исключение
... ваш процесс не прекращается немедленно. Однако вы теряете информацию, потому что .NET бесцеремонно заменяет первое исключение вторым. Поэтому блокирующий блок где-то в стеке вызовов никогда не увидит первое исключение. Тем не менее, обычно обычно больше интересуется первым исключением, потому что это обычно дает лучшие подсказки относительно того, почему все стало не так.
Так как .NET не имеет механизма для обнаружения того, выполняется ли код во время ожидания исключения, кажется, что на самом деле существует только два варианта реализации IDisposable:
- Всегда проглатывайте все исключения, которые происходят внутри Dispose(). Нехорошо, так как вы также можете усвоить OutOfMemoryException, ExecutionEngineException и т.д., Которые я обычно предпочитаю срывать процесс, когда они происходят, но уже не ожидающее другого исключения.
- Пусть все исключения распространяются из Dispose(). Нехорошо, так как вы можете потерять информацию о первопричине проблемы, см. Выше.
Итак, что является меньшим из двух зол? Есть ли лучший способ?
РЕДАКТИРОВАТЬ. Чтобы уточнить, я не говорю о том, чтобы активно отбрасывать исключения из Dispose() или нет, я говорю о разрешении исключений, созданных методами, которые Dispose() распространяет из Dispose() или нет, например:
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 assume that this might throw
}
catch
{
}
}
}