|
|
|
Supreme Being
      
участник
Last Login: 02.05.2008 1:27
Сообщ.: 313,
Visits: 2 982
|
|
| есть следующий код: try{ userSvc.CreateUser(user); } catch (Exception ex) { lblErrorString.Text = "error"; } код метода CreateUser содержит такой код: try{ ..... int errorCode = (int)errorCodeParam.Value; if (errorCode < 0) { trans.Rollback(); connection.Close(); if (errorCode == -1) { throw new DuplicateNameException(); } else { throw new Exception("Error creating User"); //throw new Exception("The provider has a user assigned to it"); } } else { trans.Commit(); connection.Close(); } } catch (Exception ex) { string msg = "User Exception : " + ex.Message; throw ex;
} Вопрос: как правильно сделать так чтобы в первой части кода, вместо lblErrorString.Text = "error"; выдавать сообщение об ошибке именно того exception которое случилось?
|
|
|
|
|
Supreme Being
модератор
Last Login: 04.05.2008 13:32
Сообщ.: 7 240,
Visits: 65 445
|
|
Этот код является прекрасной иллюстрацией как не надо работать с исключениями.- После вызова CreateUser стоит обработчик глотающий все возможные исключения. Это неправильно. Ни одна программа не в состоянии обработать все возможные исключения. Ловить надо те исключения, которые ты в состоянии обработать. Представим, что во время исполнения возникнет исключение StackOverflowException. Данный код сделает вид, что "ничего серьезного не произошло" и будет пытаться продолжить нормальное исполнение. После StackOverflowException долго он не протянет.
- Нет никакого смысла возбуждать исключение, ловить его чтобы добавить "информативное сообщение" и возбуждать его по новой. Два аргумента в защиту этого тезиса:
- Исключение это "дорогое удовольствие", которые могут сильно влиять на производительность приложения.
- Каждое исключение помнит где его вызвали, что очень важно при отладке. Твой код эту информацию теряет. Точнее источником исключения всегда будет считаться блок catch (Exception) { ... } внутри CreateUser. В данном случае, возможно, это не помеха, но в целом это неправильный подход.
- Ты используешь try/catch, но не используешь finally. Почему? Он сюда просто просится, чтобы вставить в него вызов connection.Close().
Раз тебе нужно, точно знать причину исключения, то создай свой класс или иерархию исключений, чтобы обрабатывать только их. Например: public class CreateUserException : Exception { public CreateUserException() : base("Error creating User") { } }public class DuplicateNameException : CreateUserException { private string _userName; public string UserName { get { return _userName; } } public DuplicateNameException(string userName) : base("User with name "+userName+" already exists") { _userName = userName; } } CreateUserException описывает общую ошибку создания юзера без ясной причины. DuplicateNameException уже имеет явную причину, ясную из имени. Код CreateUser мог бы выглядеть примерно так: try { ... int errorCode = (int)errorCodeParam.Value; if (errorCode < 0) { trans.Rollback(); if (errorCode == -1) { throw new DuplicateNameException(); } else { throw new CreateUserException(); } } else { trans.Commit(); } } finally { connection.Close(); } Код обработки ошибки может выглядеть так: try { userSvc.CreateUser(user); } catch (DuplicateNameException ex) { lblErrorString.Text = "Такой юзер уже существует!"; } catch (CreateUserException ex) { lblErrorString.Text = ex.Message; } Или try { userSvc.CreateUser(user); } catch (CreateUserException ex) { lblErrorString.Text = ex.Message; } Советую также прочитать заметку по теме FAQ: Why does FxCop warn against catch(Exception)?.
|
|
|
|
|
Supreme Being
      
участник
Last Login: 02.05.2008 1:27
Сообщ.: 313,
Visits: 2 982
|
|
| Bazil, спасибо за очень подробный ответ. finally я использую, просто тут не писал, а вот про кучу исключений - мне это тоже не нравится, но как сказало начальство так и приходится делать. Проверку я сделал так: if( ex.GetType().Name=="Duplicate..."){ lblError.Text="..."; } else{ ... }
|
|
|
|
|
Supreme Being
модератор
Last Login: 04.05.2008 13:32
Сообщ.: 7 240,
Visits: 65 445
|
|
californis (04.09.2006) а вот про кучу исключений - мне это тоже не нравится, но как сказало начальство так и приходится делать.Не понял. Что именно тебе сказали сделать? californis (04.09.2006)
Проверку я сделал так: if( ex.GetType().Name=="Duplicate..."){ lblError.Text="..."; } else{ ... } Это тоже плохой метод. 1) GetType() работает через рефлексию, что требует от кода наличия привилегий на ее использование и требует времени. 2) Это плохо читабельно и трудно поддерживается 3) Ты лишаешься поддержки со стороны компилятора, в случае ошибки в имени класса исключения. Лучше явно ловить нужные исключения указывая его имя в блоке catch.
|
|
|
|
|
Supreme Being
      
участник
Last Login: 02.05.2008 1:27
Сообщ.: 313,
Visits: 2 982
|
|
bazile (04.09.2006)
californis (04.09.2006) а вот про кучу исключений - мне это тоже не нравится, но как сказало начальство так и приходится делать.Не понял. Что именно тебе сказали сделать? у нас на проекте есть сходные части кода, так вот начальство решает как они должны выглядить. и выглядить они должны: 1) одинаково 2) сделаны так как скажет начальство californis (04.09.2006)
Проверку я сделал так: if( ex.GetType().Name=="Duplicate..."){ lblError.Text="..."; } else{ ... } Это тоже плохой метод. 1) GetType() работает через рефлексию, что требует от кода наличия привилегий на ее использование и требует времени. 2) Это плохо читабельно и трудно поддерживается 3) Ты лишаешься поддержки со стороны компилятора, в случае ошибки в имени класса исключения. Лучше явно ловить нужные исключения указывая его имя в блоке catch.[/quote] эта часть кода находится в try-catch.
|
|
|
|
|
Supreme Being
модератор
Last Login: 04.05.2008 13:32
Сообщ.: 7 240,
Visits: 65 445
|
|
californis (04.09.2006)
у нас на проекте есть сходные части кода, так вот начальство решает как они должны выглядить. и выглядить они должны: 1) одинаково 2) сделаны так как скажет начальство Это понятно. Меня интересует, что конкретно требует от вас начальство в плане работы с исключениями. californis (04.09.2006) эта часть кода находится в try-catch.Видимо я недостаточно ясно выразился. Представь, что в какой-то момент времени ты решишь убрать класс DuplicateNameException из программы. В случае, использования catch (DuplicateNameException) возникнет ошибка компиляции так как класс DuplicateNameException не существует. Код с проверкой на имя класса if( ex.GetType().Name=="Duplicate...") { } откомпилируется без проблем. На мой взгляд, это явный признак плохо написанного кода. Или такой стиль и есть одно из требований?
|
|
|
|
|
Supreme Being
      
участник
Last Login: 02.05.2008 1:27
Сообщ.: 313,
Visits: 2 982
|
|
Меня интересует, что конкретно требует от вас начальство в плане работы с исключениями.
допустим есть некая сходная часть кода которая проверяет ту же функциональность. и там написано, например: catch (Exception ex) { string msg = "User Exception : " + ex.Message; throw ex; } значит в своей части кода, обязательно надо написать точно также: catch (Exception ex) { string msg = "User Exception : " + ex.Message; throw ex; }
Видимо я недостаточно ясно выразился. Представь, что в какой-то момент времени ты решишь убрать класс DuplicateNameException из программы. В случае, использования catch (DuplicateNameException) возникнет ошибка компиляции так как класс DuplicateNameException не существует. Код с проверкой на имя класса if( ex.GetType().Name=="Duplicate...") { } откомпилируется без проблем. На мой взгляд, это явный признак плохо написанного кода. Или такой стиль и есть одно из требований?
класс убирать конечно же никто не будет. возможно я не точно описал изначальный код, привожу его еще раз:
подробнее: есть код:
try{ userSvc.CreateUser(user); } catch (Exception ex) { lblErrorString.Text = "error"; } есть класс и метод вызываемый: try{ ..... int errorCode = (int)errorCodeParam.Value; if (errorCode < 0) { trans.Rollback(); connection.Close(); if (errorCode == -1) { throw new DuplicateNameException(); } else { throw new Exception("Error creating User"); } } else { trans.Commit(); connection.Close(); } } catch (Exception ex) { string msg = "User Exception : " + ex.Message; throw ex; } есть также класс для DuplicateNameException: public class DuplicateNameException : Exception { public DuplicateNameException() : base() { }
public DuplicateNameException(string message) : base(message) { } public DuplicateNameException(string message, Exception innerException) : base (message, innerException) { } }
|
|
|
|
|
|
| | |