簡體   English   中英

將參數傳遞給Backgroundworker錯誤處理程序

[英]Passing argument to Backgroundworker error handler

我的程序必須同時在不同的插槽中測試幾種產品。 如果在插槽中出現錯誤(例如意外從計算機上卸下),則該程序應將用戶啟動UI時提供的錯誤類型和產品序列號記錄到文本文件中。

我正在使用Background Worker來處理多線程。 雖然我設法使用e.Error記錄了錯誤類型,但似乎無法弄清楚如何將序列號從DoWork函數傳遞給Background Worker錯誤處理程序。

我嘗試使用谷歌搜索解決方案,但似乎以前沒人問過。 我將非常感謝您提供的任何幫助。 PS:我對C#還是很陌生,所以要小心哈哈:)

下面是一個示例代碼:

        private void startAsync_Click(object sender, EventArgs e)
        {
            if (backgroundWorker1.IsBusy != true)
            {
                // Start the asynchronous operation.
                backgroundWorker1.RunWorkerAsync();
            }
        }

        private void cancelAsync_Click(object sender, EventArgs e)
        {
            if (backgroundWorker1.WorkerSupportsCancellation == true)
            {
                // Cancel the asynchronous operation.
                backgroundWorker1.CancelAsync();
            }
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;

            int b = 0; //simulate error
            for (int i = 1; i <= 10; i++)
            {
                if (worker.CancellationPending == true)
                {
                    string[] array2 = { "1", "cancelled" };
                    e.Result = array2; //passing values when user cancel through e.Result object
                    e.Cancel = true;
                    break;
                }
                else
                {
                    // Perform a time consuming operation and report progress.
                    worker.ReportProgress(i * 10, "Test a");
                    int a = 1 / b; //simulate error
                    System.Threading.Thread.Sleep(1000);

        }
                string[] array1 = {"1","done"};
                e.Result = array1; //passing values when complete through e.Result object
            }
        }

        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            resultLabel.Text = e.ProgressPercentage.ToString() + "%" + e.UserState.ToString();
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Cancelled == true)
            {
                string[] someArray2 = e.Result as string[];
                string sernum = someArray2[0];
                string status = someArray2[1];
                resultLabel.Text = sernum + " " + status;
            }
            else if (e.Error != null)
            {
                resultLabel.Text = "Error: " + e.Error.Message; //how to pass sernum here?
            }
            else
            {
                string[] someArray = e.Result as string[];
                string sernum = someArray[0];
                string status = someArray[1];
                resultLabel.Text = sernum + " " + status;

            }
        }

請參見下面的代碼。 你不需要上課。 可以使用類似的代碼簡單地發送字符串或整數。

        public class Parameters
        {
            public string message = "";
        }

        private void startAsync_Click(object sender, EventArgs e)
        {
            if (backgroundWorker1.IsBusy != true)
            {
                // Start the asynchronous operation.
                Parameters parameters = new Parameters() { message = "The quick brown fox jumped over the lazy dog" };


                backgroundWorker1.RunWorkerAsync(parameters);
            }
        }



        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            Parameters parameters = e.Argument as Parameters;
        }

在發生異常的情況下,有很多不同的方法可以將數據返回到RunWorkerCompleted事件處理程序。

恕我直言,從語義的角度來看,最自然的是將數據放入異常本身。 例如:

class BackgroundWorkerException : Exception
{
    public string Sernum { get; }

    public BackgroundWorkerException(string sernum, Exception inner)
        : base("DoWork event handler threw an exception", inner)
    {
        Sernum = sernum;
    }
}

然后在您的DoWork處理程序中:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    BackgroundWorker worker = sender as BackgroundWorker;

    try
    {
        int b = 0; //simulate error
        for (int i = 1; i <= 10; i++)
        {
            if (worker.CancellationPending == true)
            {
                string[] array2 = { "1", "cancelled" };
                e.Result = array2; //passing values when user cancel through e.Result object
                e.Cancel = true;
                break;
            }
            else
            {
                // Perform a time consuming operation and report progress.
                worker.ReportProgress(i * 10, "Test a");
                int a = 1 / b; //simulate error
                System.Threading.Thread.Sleep(1000);

            }
            string[] array1 = {"1","done"};
            e.Result = array1; //passing values when complete through e.Result object
        }
    }
    catch (Exception e)
    {
        throw new BackgroundWorkerException("1", e);
    }
}

最后,在RunWorkerCompleted事件處理程序中:

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if (e.Cancelled == true)
    {
        string[] someArray2 = e.Result as string[];
        string sernum = someArray2[0];
        string status = someArray2[1];
        resultLabel.Text = sernum + " " + status;
    }
    else if (e.Error != null)
    {
        string sernum = ((BackgroundWorkerException)e.Error).Sernum;

        resultLabel.Text = "Error: " + e.Error.Message;
    }
    else
    {
        string[] someArray = e.Result as string[];
        string sernum = someArray[0];
        string status = someArray[1];
        resultLabel.Text = sernum + " " + status;

    }
}

您的問題不清楚sernum實際代表什么,尤其是對於給定的后台任務而言,它是單個值,還是對於sernum ,單個任務可能具有多個值。 如果是前者,即您知道啟動任務時的值,則可以通過在每個實際事件處理程序使用的匿名方法中捕獲它,將其直接傳遞給事件處理程序。

如果不進行一些更改,該方法將無法在您的特定情況下起作用。 您似乎已將單個BackgroundWorker對象作為組件添加到窗體中,並且正在重用它。 如果您每次都創建一個新的BackgroundWorker ,則使用匿名方法會更好/更容易地工作,以便您可以將匿名方法委托訂閱到DoWorkRunWorkerCompleted (您必須在每次調用之前就訂閱它,因為大概每次的sernum值都不同。)

您可以在此處執行此操作,使其與添加到設計器中表單中的單個組件一起工作,但是它要復雜得多,因為您必須向RunWorkerCompleted事件動態添加處理程序,該處理程序同時取消訂閱自身和委托訂閱了DoWorkRunWorkerCompleted事件(在此方案中,您不會直接將任何方法訂閱給Designer中的組件)。

另一種選擇是創建一個自定義數據結構作為RunWorkerAsync()的參數傳遞,該結構可以包含sernum值的屬性。 您可以在啟動工作程序的方法或DoWork事件處理程序中設置此值。

這種方法僅適合您所擁有的“設計器中的組件”方案,因為您仍然需要一種將對自定義數據結構的引用返回給RunWorkerCompleted事件處理程序的方法,您只能將其存儲在例如一個可以在啟動工作程序的Click事件處理程序和RunWorkerCompleted事件之間共享的實例字段(坦率地說,如果您這樣做,那么在那個時候是否值得將該引用傳遞給RunWorkerAsync()方法是否值得爭論,因為DoWork事件處理程序也可以到達相同的實例字段。)

另一種選擇是捕獲異常,就像我在上面的代碼示例中所做的那樣,但是不要重新拋出異常,而應將其視為已取消工作(即,設置ResultCancel屬性)。

另一種方法是完全放棄BackgroundWorker並切換到基於TPL Task的習慣用法。 但這並不能隱式解決問題,但是可以使用上述任何選項,也可以只定義自己的錯誤回傳模式。

如果您需要的不是其他特定幫助,則需要發布一個新問題,並提供一個良好的“ 最小,完整和可驗證”代碼示例 ,該示例顯示了您嘗試過的上述方法之一,或未列出的其他替代方法在這里,以及您無法弄清楚的具體內容。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM