The b.RunWorkerCompleted event is where you should handle error handling. You can pass an Action<Exception> to handle errors, for example
private void GetSomething(Action<IEnumerable<int>> completedAction, Action<Exception> exceptionAction) { BackgroundWorker b = new BackgroundWorker(); b.DoWork += (s, evt) => { throw new Exception(); evt.Result = new List<int> { 1, 2, 3 }; }; b.RunWorkerCompleted += (s, evt) => { if (evt.Error == null && completedAction != null) completedAction((IEnumerable<int>)evt.Result); else if(evt.Error != null) exceptionAction(evt.Error); }; b.RunWorkerAsync(); }
However, it tends to get ugly. If you use .Net 4 or 4.5, you can resort to tasks. Task<TResult> was created just for this case:
Task<IEnumerable<int>> GetSomething() { return Task.Factory.StartNew(() => { Thread.Sleep(2000); throw new Exception(); return (new List<int> { 1, 2, 3 }).AsEnumerable(); }); }
Task is basically a signal construct with
- a
.Result property - a
.Exception property - a
.ContinueWith() method
Inside ContinueWith() you can check if Task in a bad state (exception thrown).
You can use it as
private void button3_Click(object sender, EventArgs e) { GetSomething() .ContinueWith(task => { if (task.IsCanceled) { } else if (task.IsFaulted) { var ex = task.Exception.InnerException; MessageBox.Show(ex.Message); } else if (task.IsCompleted) { var list = task.Result; foreach (int i in list) { listView1.Items.Add(new ListViewItem(i.ToString())); } } }); }
If you use .Net 4.5 and C # 5 (you need VS2012 or VS2010 and Async CTP), you can even resort to async and await as
private async void button3_Click(object sender, EventArgs e) { try { var list = await GetSomething(); foreach (int i in list) { listView1.Items.Add(new ListViewItem(i.ToString())); } } catch (Exception ex) { MessageBox.Show(ex.Message); } }
... and all the magic is done by the compiler. Please note that you can use try catch as you are used to.