c# - 如何使用委托(delegate)在线程包装器类中传递方法?

标签 c# multithreading delegates wrapper

我目前正在自学 C#,我在编程方面有点陌生,所以如果这涉及到另一个主题(我尝试搜索),请提前致歉。

我一直在尝试创建一个通用的 worker/thread 类,它采用一种方法,该方法专门包含一长串过程步骤。这个想法是能够以类似于在 Visual Studio 中设置断点以暂停/取消暂停的方式暂停/恢复它。为了提供上下文,我主要使用 ASP.NET 和 XAML WPF 接口(interface)(目前为 XAML)进行自动化。

我的理解是我需要使用某种委托(delegate),但我正在寻找一个非常简单的简单示例。我发现的示例是一个完全不同的范围,我很难在其他上下文中遵循提供的解决方案。

从 MSDN 和 Stackoverflow 上的其他示例来看,“任务”工作类是我目前所拥有的,但我对 DoDelegatedMethod 和我的构造函数的位置有点不知所措。我在这里要做的是实例化一个 Task 对象,在新实例化时传入一个委托(delegate)方法,创建一个新线程,并将传入的方法与线程结合起来。

我想要通用“任务”的原因是这样我就可以通用地管理特定方法,而不必为每个实例编写不同的“DoWork”方法。

这是正确的方法吗?

class Task
{
    private ManualResetEvent _shutdownFlag = new ManualResetEvent(false);
    private ManualResetEvent _pauseFlag = new ManualResetEvent(true);
    private delegate void MyDelegate();

    Thread _thread;

    public Task() { }

    public Task(MyDelegate d = new MyDelegate(DoStuff)) // ERROR
    {
        _thread = new Thread(DoDelegatedMethod); // ERROR
    }

    public void Start()
    {
        _thread.Start();
    }

    public void Resume()
    {
        _pauseFlag.Set(); ;
    }

    public void Stop()
    {
        _shutdownFlag.Set();
        _pauseFlag.Set();
        _thread.Join();
    }

    private void DoDelegatedMethod(MyDelegate d)
    {
        do
        {
            d();
        }
        while (!_shutdownFlag.WaitOne(0));
    }

    // This does nothing but spin forever until I force it to stop
    public void Spin()
    {
        do
        {
            // MessageBox.Show("test");
            _pauseFlag.WaitOne(Timeout.Infinite);
        }
        while (!_shutdownFlag.WaitOne(0));
        //MessageBox.Show("thread over");
    }
}

最佳答案

new Thread() 采用 ThreadStart(或 ParameterisedThreadStart)参数,而您的 DoDelegatedMethod 回调没有正确的 ThreadStart 签名。所以你需要这样写:

ThreadStart method = new ThreadStart(() => DoDelegatedMethod(d));
_thread = new Thread(method);

这会创建一个匿名回调(() => DoDelegatedMethod(d) 位),它在运行时将使用委托(delegate) d(已“捕获”)调用 DoDelegatedMethod通过匿名方法)。现在您将此匿名回调传递给 Thread 构造函数,因此当线程运行时,它将调用匿名回调,后者将依次调用 DoDelegatedMethod(d)。实际上,lambda 使 DoDelegatedMethod 适应 ThreadStart 签名。

另一种方法是将 DoDelegatedMethod 更改为不带参数,并将 d 存储为 DoDelegateMethod 将访问的 Task 类的成员字段。

此外,构造函数出错的原因是默认值只能是一组有限的类型,而委托(delegate)不是其中之一(只有属性中允许的类型,如 int、long、字符串和类型是允许的)。改用重载:

public Task() : this(new MyDelegate(DoStuff)) { ... }
public Task(MyDelegate d) { ... }

请注意,如果 DoStuff 是 Task 的实例方法,您仍然可能会收到错误消息——这并不清楚。我个人认为让 Task 运行的默认委托(delegate)设计有点奇怪,因此您可能只想摆脱默认构造函数。


根据评论中的讨论,我认为有必要总结一下对 Task 类的建议修改:

public class Task
{
  private readonly Action _action;
  // other members as before

  // default constructor removed

  public Task(Action action)
  {
    _action = action;
  }

  public void Start()
  {
    ThreadStart ts = new ThreadStart(DoDelegatedMethod);
    _thread = new Thread(ts);
    _thread.Start();
  }

  private void DoDelegatedMethod()
  {
    do
    {
      _action();
    }
    while (!_shutdownFlag.WaitOne(0));  
  }

  // other members as before
}

以及用法:

Task task = new Task(this.AutomatedTasks);
task.Start();

private void AutomatedTasks() { ... }

关于c# - 如何使用委托(delegate)在线程包装器类中传递方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4973892/

相关文章:

C# 函数委托(delegate)

c# - 如何在 C# 中为委托(delegate)类型的参数提供默认值?

c# - 将泛型方法作为参数传递给另一个方法

c# - 有没有办法测试一个字符串是否是 MD5 散列?

c# - System.Windows.Baml2006.TypeConverterMarkupExtension' 抛出异常 .' Line number ' 6' and line position ' 10

C# 二叉树的 - Inorder/Preorder 和 PostOrder(递归帮助)

java - Android 渲染和逻辑线程

Java 可重入锁和条件 |生产者完成工作,消费者陷入困境

c# - 在控制台应用程序中实例化 WinForm

java - 对 WeakReference.get() 对象的硬引用会导致内存泄漏吗?