#c# #exception-handling
#c# #исключение
Вопрос:
Мне интересно, правильно ли я обрабатываю исключения в своем коде, поэтому я надеялся, что кто-нибудь даст мне несколько мыслей о моем коде ниже
public IEnumerable<Job> GetAll() {
try {
return this._context.Jobs;
} catch (SqlException ex) {
//error so dispose of context
this.Dispose();
//wrap and rethrow back to caller
throw new CentralRepositoryException("Error getting all jobs", ex);
}
}
этот метод является частью моей бизнес-логики и вызывает метод, описанный выше
public IEnumerable<Job> GetAllJobs() {
try {
return this._jobsRepository.GetAll();
} catch (CentralRepositoryException ex) {
//logging code to go here
//throw back to caller
throw;
} catch (Exception ex) {
this._jobsRepository.Dispose();
//logging code to go here
//throw simple exception to caller
throw new CentralRepositoryException("A general exception has occurred");
}
}
мое пользовательское исключение
public class CentralRepositoryException : System.Exception {
public CentralRepositoryException(string message, Exception innerException)
: base(message, innerException) {
}
public CentralRepositoryException(string message){
}
}
Комментарии:
1. Это похоже на вопрос о проверке кода!
Ответ №1:
С этим подходом связано несколько проблем:
- Возврат
IEnumerable<T>
приведет к задержке выполнения кода. Даже если вы вернетесьIEnumerable<T>
, в коде используйтеthis._jobsRepository.GetAll().ToList();
- Отложенное выполнение приводит к тому, что обработчик ошибок вообще не вызывается, поскольку код будет выполняться с задержкой и в контексте клиента (т. Е. Везде, Где вы его используете)
- Оберните все ваши
IDisposable
объекты вusing
блок
Таким образом, альтернативой было бы:
public IEnumerable<Job> GetAllJobs() {
try {
using(var jobsRepository = new JobsRepository()) // !!! Use Dependency Injection, etc
{
return jobsRepository .GetAll().ToList(); // !! NOTE: ToList() avoids delayed execution
}
} catch (CentralRepositoryException ex) {
//logging code to go here
//throw back to caller
throw;
} catch (Exception ex) {
//logging code to go here
//throw simple exception to caller
throw new CentralRepositoryException("A general exception has occurred", ex); // !!!!!! INCLUDE THE ORIGINAL ERROR !!!!!!!
}
}
Комментарии:
1. ах, хорошо. Перенос в блок using удаляет их автоматически. я забыл об этом
2. на самом деле, думая об этом, я не хочу утилизировать после каждого вызова, поскольку это нарушает контекст. Следовательно, почему я делал это только при наличии исключения
Ответ №2:
Вы не должны просто повторно создавать исключение при потере трассировки стека. Я вижу, что вы используете их для удаления объектов, это должно быть в блоке finally.
Если вы действительно не можете обработать исключение, вам не следует использовать catch, поскольку вы хотите, чтобы он всплывал в стеке вызовов, чтобы его можно было исправить, а не скрыть.
Комментарии:
1. Он использует throw; который сохраняет стек вызовов.
2. @m.edmondson причина, по которой я удаляю объекты в предложении catch, заключается в том, что если нет исключения, объекты, которые я удаляю, все еще доступны. Есть идеи?
3. @m.edmondson я улавливаю как исключение, так и исключение centralrepositoryexception
4. @PVitt — Только если вы используете единственное число ‘throw’, но он создает
new
объект.5. который он использует по крайней мере в одном блоке catch.
Ответ №3:
Это неправильное использование Dispose() . Если вы заметили, что в конечном итоге вы пишете:
this.Dispose();
this._jobsRepository.Dispose();
Оба они ссылаются на один и тот же объект. Чтобы гарантировать, что вы удаляете только один раз, это возможность использования класса, объявляющего IDisposable для вызова dispose .
Это означает, что если вы создаете локальную переменную, вы делаете это в инструкции using:
using(SomethingDisposable foo = new SomethingDisposable())
{
//...
}
или явно утилизировать:
SomethingDisposable foo = new SomethingDisposable();
try
{
//...
}
finally
{
((IDisposable)foo).Dispose();
}
Если вы создаете поле, вы также делаете свой класс одноразовым:
class MyDisposable : IDisposable
{
private SomethingDisposable foo = new SomethingDisposable();
void IDisposable.Dispose()
{
foo.Dispose();
}
}
Если вы будете обращаться с вашими IDisposables таким образом, то ваша обработка исключений не будет путаться с вашим удалением.