Необработанные исключения в BackgroundWorker - PullRequest
65 голосов
/ 25 июня 2009

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

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

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

Согласно MSDN :

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

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

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

Ответы [ 5 ]

120 голосов
/ 25 июня 2009

То, что вы описываете, не является определенным поведением 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, вы не получите исключений во время выполнения.

36 голосов
/ 09 марта 2011

Я бы добавил к MSDN текст :

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

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

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

2 голосов
/ 21 марта 2012

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

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

1 голос
/ 25 июня 2009

[Изменить]

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

[/ 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: BOOM в BackgroundException.Form1.worker_DoWork (Объект отправитель, DoWorkEventArgs e) в D: \ Workspaces \ Sandbox \ BackgroundException \ BackgroundException \ Form1.cs: линия 43 в System.ComponentModel.BackgroundWorker.OnDoWork (DoWorkEventArgs есть System.ComponentModel.BackgroundWorker.WorkerThreadStart (Объект аргумент)

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

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

0 голосов
/ 26 апреля 2015

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...