【问题标题】:c# backgroundworker and partial classc# backgroundworker 和部分类
【发布时间】:2015-08-25 10:18:53
【问题描述】:

我在实现从 stackowerflow 获得的关于杀死后台工作进程的代码时遇到问题。

我的代码如下:

using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.Threading;
using System.Text.RegularExpressions;
using System.Runtime.InteropServices;
using GluthGUI.Classes.XMLprofile;
using System.Xml.Linq;
using System.ComponentModel;


namespace Solution
{
    partial class SolGUI : Form
    {

         private void startButton_Click(object sender, EventArgs e)
        {            



backgroundWorker1 = new AbortableBackgroundWorker();

            if (startButton.Text == "Start")
            {

                XMLParsing();


                DisableTextFields();

                backgroundWorker1.RunWorkerAsync();     

                startButton.Text = "Stop";

            }
            else if (startButton.Text == "Stop")
            {

                if (backgroundWorker1.IsBusy == true)
                {
                    backgroundWorker1.Abort();  //error Abort() is not declared?!?!
                    backgroundWorker1.Dispose();
                }

                startButton.Text = "Start";
                DisableTextFields();
            }
        }
    }

这是一个将终止 backgroundworker 的部分类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using System.Threading;

namespace Solution
{
    public class AbortableBackgroundWorker : BackgroundWorker
    {
        private Thread workerThread;

        protected override void OnDoWork(DoWorkEventArgs e)
        {
            workerThread = Thread.CurrentThread;
            try
            {
                base.OnDoWork(e);
            }
            catch (ThreadAbortException)
            {
                e.Cancel = true; //We must set Cancel property to true!
                Thread.ResetAbort(); //Prevents ThreadAbortException propagation
            }
        }


        public void Abort()
        {
            if (workerThread != null)
            {
                workerThread.Abort();
                workerThread = null;
            }
        }
    }
}

我的问题是部分类的 Abort() 方法在具有相同命名空间的其他类中不可见。

【问题讨论】:

  • 你真的需要使用 Abort 吗?在大多数情况下不建议这样做。而是使用变量或 CancellationToken。
  • 在非部分类中使用 AbortableBackgroundWorker 是否有效?
  • backgroundWorker1 在哪里(以及如何)定义?类型是AbortableBackgroundWorker?而且它永远不会很忙,因为你每次都在创建一个新实例,所以你永远不会有任何事情要中止
  • As Eric Lippert says: Thread.Abort 充其量是糟糕设计的表现,可能不可靠且极其危险。应该不惜一切代价避免它
  • 'System.ComponentModel.BackgroundWorker' 不包含'Abort' 的定义,并且找不到接受'System.ComponentModel.BackgroundWorker' 类型的第一个参数的扩展方法'Abort'(你是缺少 using 指令或程序集引用?)

标签: c# class methods backgroundworker


【解决方案1】:

问题是您使用BackgroundWorker 类型定义backgroundWorker1,因此您无权访问AbortableBackgroundWorker 类中定义的自定义方法。

要么将AbortableBackgroundWorker 直接添加到您的设计器中,要么在您的表单中手动声明AbortableBackgroundWorker

partial class SolGUI : Form
{
    AbortableBackgroundWorker backgroundWorker1 = new AbortableBackgroundWorker();

您还需要确保从按钮单击事件中删除这行代码:

backgroundWorker1 = new AbortableBackgroundWorker();

因为这会导致每次单击时都会设置一个新实例,并且您将永远无法访问原始实例以中止它。您也不应该在任何时候处置该对象,因为您希望在再次启动该过程时重用它,因此请删除:

backgroundWorker1.Dispose();

您还需要关联您正在使用的任何事件,例如DoWork。您应该像这样在表单构造函数中执行此操作:

backgroundWorker1.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker1_DoWork);

我不会详细说明您是否应该中止线程,其他人已经评论过,如果您想听从他们的建议并进行一些研究,那是您的选择。我只是简单地回答了手头的问题。不过就个人而言,我会使用内置的取消方法。

【讨论】:

  • 好的,解决了 Abort() 的问题。现在你能解释一下“hook DoWork”是什么意思吗?因为我对方法 backgroundWorker1.RunWorkerAsync(); 有问题;没有运行。
【解决方案2】:

除非DoWork事件的订阅方法是插件或者你无法维护的第3方代码,一般是very bad idea直接中止线程。

当您单击停止按钮时,您必须将取消请求传递给您的工作对象;否则,它永远不会被通知。 BackgroundWorker 有一个 CancelAsync 方法,它不做任何事情,只是简单地设置 BackgroundWorker.CancellationPending 属性,通知 BackgroundWorker 的使用者(UI,而不是执行的任务)你的任务有被取消了。

那么你需要什么:

MyWorkerObject myObject;

// This method is executed on the worker thread. Do not access your controls
// in the main thread from here directly.
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    myObject = new MyWorkerObject();

    // The following line is a blocking operation in this thread.
    // The user acts in the UI thread, not here, so you cannot do here
    // anything but wait.
    myObject.DoWork();

    // Now DoWork is finished. Next line is needed only to notify
    // the caller of the event whether a cancel has happened.
    if (backgroundWorker1.CancellationPending)
        e.Cancel = true;

    myObject = null;
}

private void btnCancel_Click(object sender, EventArgs e)
{
   if (backgroundWorker1.IsBusy)
   {
       backgroundWorker1.CancelAsync();

       // You must notify your worker object as well.
       // Note: Now you access the worker object from the main thread!
       // Note2: It would be possible to pass the worker to your object
       //        and poll the backgroundWorker1.CancellationPending from there,
       //        but that would be a nasty pattern. BL objects should not
       //        aware of the UI components.
       myObject.CancelWork();
   }
}

你应该如何实现通知:

public class MyWorkerObject
{
    // normally you should use locks to access fields from different threads
    // but if you just set a bool from one thread and read it from another,
    // then it is enough to use a volatile field.
    private volatile bool isCancelRequested;

    // this will be called from the main thread
    public void CancelWork()
    {
        isCancelRequested = true;
    }

    // This method is called from the worker thread.
    public void DoWork()
    {
        // Make sure you poll the isCancelRequested field often enough to
        // react to the cancellation as soon as possible.
        while (!isCancelRequested && ...)
        {
            // ...
        }
    }
}

【讨论】:

    【解决方案3】:

    变量backgroundWorker1 已被定义为BackgroundWorker,而它应该在部分类的另一部分中定义为AbortableBackgroundWorker

    也许您可以在解决方案资源管理器中以 SolGUI.Desinger.cs 的形式找到它。

    【讨论】:

      【解决方案4】:
      backgroundWorker1 = new AbortableBackgroundWorker();
      

      这一行是问题所在,每次单击按钮时都会创建一个新的后台工作者实例。 您应该定义是否在方法之外 应该没问题的

      【讨论】:

      • 那不能解决编译代码的问题,需要把类型改成AbortableBackgroundWorker
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-12-01
      • 1970-01-01
      • 2020-11-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多