Приветствую всех!
Я пытаюсь разработать класс, который интенсивно использует System.Net.Sockets.TcpClient. Предполагается, что данный класс будут использовать другие программисты. По крайней мере, я, позднее.
Есть метод класса ConnectToServer, единственная задача которого — установить TCP-соединение с сервером на определенном порту и получить сетевой поток.
Connect(strServer, port)
Метод Connect(string hostname, int port) класса System.NET.Sockets.TcpClient может возбуждать следующие исключения:
ArgumentNullException, если ссылка hostname == null;
ArgumentOutOfRangeException, если порт не в диапазоне [System.Net.IPEndPoint.MinPort; System.Net.IPEndPoint.MaxPort];
SocketException при возникновении ошибки доступа к сокету (кратко);
ObjectDisposedException — означает, что при TcpClient закрыт.
В Debug-версии первые два исключения предотвращаются предварительной проверкой аргументов через утверждения.
Однако, я не могу никак определиться, что делать со всеми этими исключениями.
Первый вариант — создать свой класс исключений, производный от ApplicationException, обернуть вызов Connect(...) в try/catch:
CException inner = null;
try
{
Connect(sServername, 111);
}
catch(ArgumetNullException ex)
{
inner = ex;
}
catch(ArgumentOutOfRangeException ex)
{
inner = ex;
}
catch(SocketException ex)
{
inner = ex;
}
catch(ObjectDisposedException)
{
inner = ex;
}
if ( inner != null ) throw new MyPersonalException("Unable to connect", inner);
Второй вариант — констатировать в комментариях к методу ConnectToServer, что метод может возбуждать такие-то исключения и перечислить их все, т.е. переложить груз ответственности по обработке исключений на разработчика, который будет пользоваться этим классом.
Либо,
третий вариант — локализовать всякие исключения на уровне класса, а результат выполнения метода возвращать в статусной переменной.
Вообще, этот вопрос актуален для всех методов класса. То есть интересуют советы профессионалов: "
Как правильно управлять ошибками времени выполнения"?
Подобный вопрос про проверку, подобную Debug.Assert(strServer != null, "strServer is NULL") перед вызовом Connect(...) в Release-версии. И нужно ли вообще это делать, ведь, вроде как Connect сам возбуждает исключение, если strServer будет null?
Хочется писать программы грамотно.
Спасибо.
Здравствуйте, assm-spb, Вы писали:
AS>Второй вариант — констатировать, что метод может возбуждать такие-то исключения и перечислить их все, т.е. переложить груз ответственности по обработке исключений на разработчика, который будет пользоваться этим классом.
Посмотрите вот эти два определения:
Design by contract и
Defensive programming. По большому счету, Defensive programming есть зло,
если проверки осуществляются более чем в одном месте (например, в самой функции есть проверка параметра на null и в модуле, вызывающем, эту функцию тоже есть такая проверка).
Чтобы избежать таких ситуаций, пользуются DBC (Design by contract). Это означает, что обе стороны (допустим, разработчик модуля и клиент, использующий его) договариваются по этому поводу заранее — кто обязан выполнять проверки.
В теории это соглашение должно быть письменное и подписывается обеями сторонами (дабы в случае багов избежать дальнейших выяснений, кто виноват). Но это, ИМХО, встречается лишь в конторах с сильно формализованным процессом.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Здравствуйте, assm-spb, Вы писали:
Не всё так однозначно. Скажем, ArgumetNullException и ArgumentOutOfRangeException лучше не перехватывать, так как к "Unable to connect" они имеют слабое отношение. Это диагностика некорректности параметров и она таковой и должна остаться.
ObjectDisposedException опять таки не на пустом месте берётся. Значит у тебя баг. Его надо править, а не отправлять выше по уровню невменяемое сообщение. В корректном коде ObjectDisposedException не бывает.
Остался SocketException. Чего же его оборачивать?
Здравствуйте, assm-spb, Вы писали:
AS>Хочется писать программы грамотно.
AS>Спасибо.
Думаю, не будет лишним и прочтение
этого документа.
С уважением,
OldDino