2009-06-25 3 views
59

У меня есть небольшое приложение WinForms, которое использует объект BackgroundWorker для выполнения долговременной операции.Необработанные исключения в BackgroundWorker

Фоновая операция вызывает случайные исключения, обычно, когда у кого-то есть открытый файл, который воссоздается.

Независимо от того, выполняется ли код из среды IDE или нет, появляется диалоговое окно с сообщением об ошибке, информирующее пользователя о том, что произошло необработанное исключение. Компиляция кода с использованием конфигурации Release также не изменит этого.

По MSDN:

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

Я ожидаю, что эти исключения будут выбрасываться по случаю и будут обрабатывать их в событии RunWorkerCompleted, а не в DoWork. Мой код работает правильно, и ошибка обрабатывается правильно в событии RunWorkerCompleted, но я не могу на всю жизнь понять, как остановить диалог ошибок .NET, жалующийся на появление «необработанного исключения».

Разве фоновая работа не должна ломать эту ошибку автоматически? Не то, что говорится в документации MSDN? Что мне нужно сделать, чтобы сообщить .NET, что эта ошибка - это, которая обрабатывается, но все же позволяет исключению просачиваться в свойство Error RunWorkerCompletedEventArgs?

ответ

104

То, что вы описываете не определено поведение BackgroundWorker. Я подозреваю, вы делаете что-то неправильно.

Вот небольшой пример, который доказывает BackgroundWorker ест исключения в DoWork, и делает их доступными для вас в RunWorkerCompleted:

var worker = new BackgroundWorker(); 
worker.DoWork += (sender, e) => 
    { 
     throw new InvalidOperationException("oh shiznit!"); 
    }; 
worker.RunWorkerCompleted += (sender, e) => 
    { 
     if(e.Error != null) 
     { 
      MessageBox.Show("There was an error! " + e.Error.ToString()); 
     } 
    }; 
worker.RunWorkerAsync(); 

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

var worker = new BackgroundWorker(); 
worker.DoWork += (sender, e) => 
    { 
     throw new InvalidOperationException("oh shiznit!"); 
    }; 
worker.RunWorkerCompleted += (sender, e) => 
    { 
     // OH NOOOOOOOES! Runtime exception, you can't access e.Result if there's an 
     // error. You can check for errors using e.Error. 
     var result = e.Result; 
    }; 
worker.RunWorkerAsync(); 

Вот собственно реализация обработчика событий RunWorkerCompleted:

private void RunWorkerCompletedHandler(object sender, RunWorkerCompletedEventArgs e) 
{ 
    if (e.Error == null) 
    { 
     DoSomethingWith(e.Result); // Access e.Result only if no error occurred. 
    } 
} 

VOILA, вы выиграли» t получать исключения во время выполнения.

+0

+1 Хорошая точка. В моем примере указана специфика обработки ошибки, но мой код действительно вызовет другое исключение, если исключение никогда не попадало в методе DoWork. –

+0

Я прошу различить .... Я также изо всех сил пытаюсь понять, как класс BGW ест вверх, потому что иногда мое приложение предоставляет мне доступ к моей пользовательской области на Win7, а иногда и нет. Когда я исследую далее, я обнаружил, что отказ в доступе обусловлен тем, что папка не существует. Я считаю, что иногда ошибка возникает в моем приложении, а иногда и нет. – IbrarMumtaz

+0

@Ibrar, вы всегда проверяете e.Error внутри обработчика события RunWorkerCompleted? Убедитесь, что вы проверили это, прежде чем что-либо сделать. Об этом можно узнать обо всех доступных исключениях. –

1

[изменить]

У Иуды отличная точка. В моем примере указана специфика обработки ошибки, но мой код действительно вызовет другое исключение, если исключение никогда не попадало в методе DoWork. Этот пример в порядке из-за того, что мы специально показываем возможности обработки ошибок BackgroundWorker. Однако, если вы не проверяете параметр ошибки на значение null, это может быть вашей проблемой.

[/ Edit]

Я не вижу те же результаты. Можете ли вы разместить небольшой код? Вот мой код.

private void Form1_Load(object sender, EventArgs e) 
{ 
    BackgroundWorker worker = new BackgroundWorker(); 
    worker.DoWork += new DoWorkEventHandler(worker_DoWork); 
    worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted); 
    worker.RunWorkerAsync(); 
} 

void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
{ 
    // Will cause another exception if an exception didn't occur. 
    // We should be checking to see if e.Error is not "null". 
    textBox1.Text = "Error? " + e.Error; 
} 

void worker_DoWork(object sender, DoWorkEventArgs e) 
{ 
    for (int i = 0; i < 10; i++) 
    { 
     if (i < 5) 
     { 
      Thread.Sleep(100); 
     } 
     else 
     { 
      throw new Exception("BOOM"); 
     } 
    } 
} 

Программа выхода:

Ошибка? System.Exception: БУМ в BackgroundException.Form1.worker_DoWork (Object отправителя, DoWorkEventArgs е) в D: \ Рабочие области \ Песочница \ BackgroundException \ BackgroundException \ Form1.cs: линия 43 на System.ComponentModel.BackgroundWorker.OnDoWork (DoWorkEventArgs е) в System.ComponentModel.BackgroundWorker.WorkerThreadStart (Object аргумент)

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

http://www.developerdotstar.com/community/node/671

34

Я хотел бы добавить к MSDN text:

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

... И отладчик сообщит исключение, как «~ Исключение было необработанное пользователем кода»

Решение: Не работает под отладчиком, и она работает, как ожидалось: Исключение пойманы в e.Error.

+3

Спасибо за это. Я действительно хотел бы знать, почему на самом деле это так. Невозможно отладить обработку исключений события RunWorkerCompleted. –

+0

Если бы они только что положили этот бит об отладчике в документацию ... Так верно. Благодарю. – andersop

+1

@yu_ominae: Не невозможно. Всякий раз, когда отладчик разбивается на исключение, вы можете фактически нажать F5 (Продолжить), чтобы BackgroundWorker поймал исключение, и выполнение продолжится, как ожидалось, в «RunWorkerCompleted». –

2

Это старый вопрос, но я нашел его, в то время как у Гуглинга были те же симптомы. Проводя это, если кто-то другой найдет его по той же причине.

Ответ Иуды прав, но это не единственная причина, по которой может появиться диалоговое окно «необработанное исключение в пользовательском коде». Если исключение вызывается из конструктора в фоновом потоке, то это исключение вызовет диалог сразу и не будет передано в событие RunWorkerCompleted. Если вы перемещаете нарушающий код вне любых конструкторов (любым другим способом), он работает так, как ожидалось.

+0

Я попытался бросить исключение в конструкторе, и «RunWorkerCompleted» поймал его. Возможно, вы попробовали его с помощью консольного приложения? Согласно [этому ответу] (http://stackoverflow.com/a/10299830/939213), консольные приложения ведут себя по-разному. – ispiro

+0

Возможно. Конкретные исключения, с которыми я столкнулся, были даны мне: «Инициализатор типа для xyz выбрасывал исключения», я не уверен, какие конкретные обстоятельства могут произвести это. – Rich

+0

Старая нить, но помнила остальную часть этой истории - исключение TypeInitializationException это тот, о котором я думал, и он возникает, если исключение возникает внутри конструктора * static *. – Rich

0

У меня была такая же проблема, и я уже применял ответ Иуды, прежде чем я нашел эту тему после некоторых поисковых запросов.

Ну, Имо ответ Иуды частично правильный. Я нашел лучший ответ here

Отладчик отлично работает, если вы запускаете приложение в «реальных условиях», RunWorkerCompleted имеет дело с исключением, как ожидалось, и поведение приложения также ожидается.

Надеюсь, этот ответ поможет.

+0

[Этот более ранний ответ] (http://stackoverflow.com/a/5244908/1497596) описывает, что происходит в отладчике Visual Studio. – DavidRR

Смежные вопросы