Как правильно обрабатывать ошибки?
От: assm-spb Россия  
Дата: 08.10.07 18:55
Оценка:
Приветствую всех!

Я пытаюсь разработать класс, который интенсивно использует 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?
Хочется писать программы грамотно.
Спасибо.
Re: Как правильно обрабатывать ошибки?
От: Дюша Россия http://www.danfoss.com/russia
Дата: 08.10.07 19:23
Оценка:
Здравствуйте, assm-spb, Вы писали:

AS>Второй вариант — констатировать, что метод может возбуждать такие-то исключения и перечислить их все, т.е. переложить груз ответственности по обработке исключений на разработчика, который будет пользоваться этим классом.


Посмотрите вот эти два определения: Design by contract и Defensive programming. По большому счету, Defensive programming есть зло, если проверки осуществляются более чем в одном месте (например, в самой функции есть проверка параметра на null и в модуле, вызывающем, эту функцию тоже есть такая проверка).
Чтобы избежать таких ситуаций, пользуются DBC (Design by contract). Это означает, что обе стороны (допустим, разработчик модуля и клиент, использующий его) договариваются по этому поводу заранее — кто обязан выполнять проверки.

В теории это соглашение должно быть письменное и подписывается обеями сторонами (дабы в случае багов избежать дальнейших выяснений, кто виноват). Но это, ИМХО, встречается лишь в конторах с сильно формализованным процессом.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>

Re: Как правильно обрабатывать ошибки?
От: adontz Грузия http://adontz.wordpress.com/
Дата: 09.10.07 03:20
Оценка:
Здравствуйте, assm-spb, Вы писали:

Не всё так однозначно. Скажем, ArgumetNullException и ArgumentOutOfRangeException лучше не перехватывать, так как к "Unable to connect" они имеют слабое отношение. Это диагностика некорректности параметров и она таковой и должна остаться.

ObjectDisposedException опять таки не на пустом месте берётся. Значит у тебя баг. Его надо править, а не отправлять выше по уровню невменяемое сообщение. В корректном коде ObjectDisposedException не бывает.

Остался SocketException. Чего же его оборачивать?
A journey of a thousand miles must begin with a single step © Lau Tsu
Re: Как правильно обрабатывать ошибки?
От: OldDino Россия  
Дата: 09.10.07 05:14
Оценка:
Здравствуйте, assm-spb, Вы писали:

AS>Хочется писать программы грамотно.

AS>Спасибо.

Думаю, не будет лишним и прочтение этого документа.

С уважением,

OldDino
Re: Как правильно обрабатывать ошибки?
От: stump http://stump-workshop.blogspot.com/
Дата: 09.10.07 05:19
Оценка:
Здравствуйте, assm-spb, Вы писали:

Ты разрабатываешь библиотесный класс. Посмотри как сделана обработка исключений в других библиотечных классах и делай так же. Например, в том же TcpClient. Общее правило такое: библиотечный класс возбуждает исключение, а код который использует библиотесный класс обрабатывает исключение. К сожалению, в отличие от Java в C# нельзя указать в контракте класса, какие исключения он может генерировать, поэтому это надо указывать хотя бы в документации к классу.
Оборачивать исключения, возникающие внутри библиотечного класса в свой собственный класс исключений имеет смысл только в случае, когда твой класс вводит новый уровень абстракции. Например, класс реализует некий прикладной протокол взаимодействия поверх TCP. Тогда имеет смысл упаковывать ошибки валидации входных данных и ошибки транспортного уровня TCP в свое исключение, чтобы представить их уже в терминах своего прикладного протокола. При этом обязательно следует сохранять исходное исключение в InnerException.
Понедельник начинается в субботу
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.