我有一個相當複雜的程序,所以我不會在這裏存儲所有東西。下面是一個簡化版本:C# - 後臺工作人員?
class Report {
private BackgroundWorker worker;
public Report(BackgroundWorker bgWorker, /* other variables, etc */) {
// other initializations, etc
worker = bgWorker;
}
private void SomeCalculations() {
// In this function, I'm doing things which may cause fatal errors.
// Example: I'm connecting to a database. If the connection fails,
// I need to quit and have my background worker report the error
}
}
// In the GUI WinForm app:
// using statements, etc.
using Report;
namespace ReportingService {
public partial class ReportingService : Form {
// My background worker
BackgroundWorker theWorker = new BackgroundWorker() {
WorkerReportsProgress = true
};
// The progress changed event
void worker_ProgressChanged(object sender, ProgressChangedEventArgs e) {
// e.UserState and e.ProgressPercentage on some labels, etc.
}
// The do work event for the worker, runs the number crunching algorithms in SomeCalculations();
void worker_DoWork(object sender, DoWorkEventArgs e) {
Report aReport = e.Argument as Report;
aReport.SomeCalculations();
}
// The completed event, where all my trouble is. I don't know how to retrieve the error,
// or where it originates from.
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
// How, exactly, do I get this error message? Who provides it? How?
if (e.Error != null) {
MessageBox.Show("Error: " + (e.Error as Exception).ToString());
}
else if (e.Cancelled) {
MessageBox.Show("Canceled");
}
// operation succeeded
else {
MessageBox.Show("Success");
}
}
// Initialization of the forml, etc
public ReportingService() {
InitializeComponent();
theWorker.ProgressChanged += worker_ProgressChanged;
theWorker.DoWork += worker_DoWork;
theWorker.RunWorkerCompleted += worker_RunWorkerCompleted;
}
// A button that the user clicks to execute the number crunching algorithm
private void sumButton_Click(object sender, EventArgs e) {
Report myReport = new Report(theWorker, /* some other variables, etc */)
theWorker.RunWorkerAsync(myReport);
}
}
}
這裏是我的邏輯,並請糾正我,如果我要對這個錯誤的方法:
我抽象類出來的GUI的,因爲它是〜2000行和需要成爲它自己的自我包含的對象。
我將後臺工作者傳入我的課程,以便我可以報告我的數字處理進度。
我不知道該怎麼做是讓後臺工作人員知道我的課內發生了錯誤。爲了使RunWorkerCompleted參數成爲一個異常,我的try/catch塊需要去哪裏,我應該在catch塊中做什麼?
感謝您的幫助!
編輯:
我試過下面的東西來測試錯誤處理:
記住我破壞我的數據庫連接字符串故意收到一條錯誤消息。
在我的班級我做的:
// My number crunching algorithm contained within my class calls a function which does this:
// try {
using (SqlConnection c = GetConnection()) { // note: I've corrupted the connection string on purpose
c.Open(); // I get the exception thrown here
using (SqlCommand queryCommand = new SqlCommand(query, c)) { /* Loop over query, etc. */ }
c.Close();
}
// } catch (Exception e) { }
1. 從我的理解,未處理的異常被強制轉換爲RunWorkerCompletedEventArgs
的Error
部分?當我嘗試這一點,我得到如下:
// In my winform application I initialize my background worker with these events:
void gapBW_DoWork(object sender, DoWorkEventArgs e) {
Report aReport = e.Argument as Report;
Report.Initialize(); // takes ~1 minute, throws SQL exception
Report.GenerateData(); // takes around ~2 minutes, throws file IO exceptions
}
void gapBW_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
if (e.Error != null) { // I can't get this to trigger, How does this error get set?
MessageBox.Show("Error: " + (e.Error as Exception).ToString());
}
else if (e.Cancelled) {
MessageBox.Show("Canceled: " + (e.Result).ToString());
}
else {
MessageBox.Show("Success");
}
}
Visual Studio的說,我的應用程序扼流圈c.Open()
與未處理的異常失敗。
2. 當我把一個try/catch塊在我的DoWork功能:
void gapBW_DoWork(object sender, DoWorkEventArgs e) {
try {
Report aReport = e.Argument as Report;
aReport.Initialize(); // throws SQL exceptions
aReport.GenerateData(); // throws IO file exceptions
}
catch (Exception except) {
e.Cancel = true;
e.Result = except.Message.ToString();
}
}
void gapBW_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
if (e.Error != null) { // I can't get this to trigger, How does this error get set?
MessageBox.Show("Error: " + (e.Error as Exception).ToString());
}
else if (e.Cancelled) {
MessageBox.Show("Canceled: " + (e.Result).ToString());
}
else {
MessageBox.Show("Success");
}
}
我得到了TargetInvocationException
了未處理的Program.cs中的自動生成Application.Run(new ReportingService());
線。我在RunWorkerCompleted上放置了一個斷點,並可以看到e.Cancelled = true,e.Error = null和e.UserState = null。 e.Cancelled中包含的信息僅僅是「操作已被取消」。我想我從e.Result的無效轉換中收到TargetInvocationException
(因爲它爲空)。我想知道的是,e.Error是如何來的,e.Canceled沒有包含任何有用的信息爲什麼的操作被取消了?
3. 當我試圖從內部的DoWork對異常俘獲設置e.Canceled = true;
,我設法觸發我RunWorkerCompleted
功能else if (e.Cancelled) {
線。我以爲這是保留給請求作業被取消的用戶呢?我從根本上誤解了後臺工作人員的功能?
感謝大家的幫助,但這最終解決了我的問題。原來這個問題不是我對C#的誤解,而是我對Visual Studio的誤解。我養成了按F5運行我的程序的習慣,並認爲當一個異常未處理時,程序會崩潰。我沒有意識到你可以再次按下F5繼續處理。 –
另外不要忘記按下F10,F11和Shift-F11的功能。 ;-)) – Oliver
也許看看[這個問題](http://stackoverflow.com/questions/1044460/unhandled-exceptions-in-backgroundworker/1044610#1044610)也幫助你了。 – Oliver