Необработанные исключения в BackgroundWorker


мое приложение WinForms использует ряд BackgroundWorker предметы для извлечения информации из базы данных. Я использую BackgroundWorker, потому что он позволяет пользовательскому интерфейсу оставаться разблокированным во время длительных запросов к базе данных, и это упрощает потоковую модель для меня.

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

мой вопрос о том, что происходит, когда необработанное исключение возникает в одном из этих фоновых рабочих потоков.

Я не думаю, что могу поймать исключение в другом потоке, но могу ли я ожидать, что мой WorkerCompleted метод будет выполнен? Есть ли какое-либо свойство или метод BackgroundWorker, который я могу опросить для исключений?

5 71

5 ответов:

Если операция вызывает исключение, что ваш код не обрабатывает тег BackgroundWorker ловит исключение и передает его в RunWorkerCompleted обработчик событий, где он представлен как свойство ошибки System.ComponentModel.RunWorkerCompletedEventArgs. Если вы работаете под отладчиком Visual Studio, отладчик сломается в точке обработчика событий DoWork, где было необработанное исключение поднятый.

http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.dowork.aspx

я полностью использую BackgroundWorker на протяжении многих лет и действительно знаю это в глубине души.

совсем недавно, мой RunWorkerCompleted не поймать e.Error когда я просто Throw New Exception("Test") на DoWork. Однако возникло необработанное исключение. Лови в DoWork - это не лучшая практика, таким образом e.Error нет смысла.

когда я пытаюсь создать новый Form новые BackgroundWorker,e.Error на RunWorkerCompleted успешно справились. Там должно быть что-то не так в моей сложной BackgroundWorker.

после a несколько дней гуглил и отлаживал, пробовал ошибку. Я нашел это в моем RunWorkerCompleted:

  • проверить e.Error во-первых, тогда e.Cancelled и наконец e.Result
  • не получается e.Result если e.Cancelled = True.
  • не получается e.Result если e.Error не null (или Nothing)**

* * вот где я скучаю. Если вы пытаетесь использовать e.Result если e.Error не null (или Nothing), необработанное исключение заброшенный.


обновление: В e.Result получить свойство .NET дизайн его для проверки e.Error во-первых, если получил ошибку, то они будут повторно бросить то же исключение из DoWork. Вот почему мы получаем необработанное исключение в RunWorkerCompleted но на самом деле исключение приехал из DoWork.

вот лучшая практика, чтобы сделать в RunWorkerCompleted:

If e.Error IsNot Nothing Then
  ' Handle the error here
Else
  If e.Cancelled Then
    ' Tell user the process canceled here
  Else
    ' Tell user the process completed
    ' and you can use e.Result only here.
  End If
End If

если вы хотите объект, который доступен для всех DoWork, ProgressChanged и RunWorkerCompleted, используйте вот так:

Dim ThreadInfos as Dictionary(Of BackgroundWorker, YourObjectOrStruct)

вы можете легко получить доступ к ThreadInfos(sender).Field везде, где вы хотите.

по умолчанию он будет пойман и сохранен BackgroundWorker. От MSDN:

Если операция вызывает исключение, которое ваш код не обрабатывает, BackgroundWorker ловит исключение и передает его в обработчик событий RunWorkerCompleted, где оно предоставляется как свойство Error системы.ComponentModel.RunWorkerCompletedEventArgs. Если вы работаете под отладчиком Visual Studio, отладчик сломается в точке обработчика событий DoWork где возникло необработанное исключение.

Как уже отмечалось:

Если операция вызывает исключение что ваш код не обрабатывает, в BackgroundWorker перехватывает исключение и передает его в Обработчик события RunWorkerCompleted , где он выставляется как ошибка собственность Система.ComponentModel.RunWorkerCompletedEventArgs.

Это важно, когда вы взаимодействуете с исходным потоком. Например, если вы хотите, чтобы результат вашего исключения будет написано в какой-то метке на вашей форме, вот когда вы не должны ловить исключение в DoWork BackgroundWorker, а вместо этого обрабатывать e.Error от RunWorkerCompletedEventArgs.

Если вы проанализируете код BackgroundWorker с отражателем, вы можете увидеть, что все это обрабатывается довольно просто: Ваш DoWork выполняется в блоке try-catch, и исключение просто передается в RunWorkerCompleted. Вот почему я не согласен с "предпочтительным" методом всегда ловить все исключения в случае метода dowork.

короче, чтобы ответить на исходный вопрос:

да - вы можете рассчитывать на то, что ваш RunWorkerCompleted всегда будет уволен.

использовать Эл.Ошибка из RunWorkerCompleted, чтобы проверить наличие исключений в другом потоке.

Это будет работать только без подключенного отладчика, при запуске из Visual Studio отладчик поймает необработанное исключение в методе DoWork и нарушит выполнение, однако вы можете нажать кнопку Продолжить, и RunWorkerCompleted будет достигнут, и вы сможете прочитать исключение через поле e.Error.