【问题标题】:Task start/stop handling using abstract classes使用抽象类的任务启动/停止处理
【发布时间】:2018-12-12 20:59:23
【问题描述】:

我有这个代码逻辑来处理我的任务:

public abstract class BaseJob{

    public bool Running { get; private set; }

    public CancellationToken Token => _tokenSource.Token;

    private CancellationTokenSource _tokenSource;

    public virtual void Start()
    {
        _tokenSource = new CancellationTokenSource();
        Running = true; 
    }
}

现在当我继承BaseJob我就会出现这种情况:

public class CustomJob: BaseJob{

public MyEnum Status {get; private set;}

public StopRequested { get; set;}

public override async void Start(){

    base.Start();
    while(!StopRequested){
        await MyLongRunningMethod();
    }

    //base.Running = true but I can't access it here!
}

public async Task<bool> MyLongRunningMethod(){  
            await Task.Run(()=>{
                //more work
            },this.Token);
            //someWork

    return false;
}
}

如您所见,我无法在 myJob 完成后立即访问 Running 将其设置为 false,我希望 BaseJob 处理该问题。

为了自动检测myJob 何时完成,我必须对基类进行哪些代码逻辑更改,然后使用Running = false 完成任务,而无需从继承的类中访问最少?

【问题讨论】:

  • 那么为什么要编写自己的任务对象而不是使用System.Threading.Tasks.Task?您甚至将 TPL 标记为相关,但您……没有使用它。
  • @Servy 我有一个基本上是机器人的程序,它运行大量不同的任务。这就是为什么,我需要一个比 TPL 任务更复杂的结构。哦,顺便说一句,当我在自定义任务中运行“作业”时,我也使用 TPL 任务。
  • 然而你的“任务”实际上并没有做任何 TPL 任务没有做的事情。您的问题最好通过一种方法来完成工作并返回常规 TPL Task。如果有什么你需要做但没有涵盖的,你肯定没有展示出来。
  • @Servy 显示的代码太多了。我让它尽可能简单,但我保证它比 TPL 任务做的更多。
  • @garryman 仍然没有看到任何理由不只是有一个返回 Task 的方法。 TPL 任务有一个错误,它可以有一个取消令牌,它有一个状态。您可以编写一个方法来检查取消令牌并在未取消时运行异步操作,并且此类方法可以返回 Task 为此类异步方法的调用者提供与您的 Task 版本一样多的信息. (具有 TPL 任务具有更多功能的优点,并且可以与 .NET 和 C# 中的各种任务感知功能一起使用。)

标签: c# oop inheritance task abstract-class


【解决方案1】:

您可以重写您的抽象类,使其具有一个可以知道您的工作何时完成的内部启动方法。假设你的工作是同步的并且没有参数:

public abstract class BotTask
{

    private bool Running { get; set; }

    public CancellationToken Token => _tokenSource.Token;

    private CancellationTokenSource _tokenSource;

    public abstract void Start();

    protected void InternalStart(Action job)
    {
        _tokenSource = new CancellationTokenSource();
        Running = true;
        job();
        Running = false;
    }
}

public class CustomTask : BotTask
{
    public override void Start()
    {
        InternalStart(MyJob);
    }
}

【讨论】:

  • 这正是我开始接近的道路。但是,Action job 本身就是一项任务。具有子任务的任务,所有子任务都必须使用取消令牌。假设Action jobCustomTask 类中定义的私有Task 方法,您能否编辑您的答案并实现它?我在基类中实现 Task.Run 方法的部分卡住了(还要注意它必须在线程池中运行,我不希望 UI 卡住。
  • 你能在你的问题中展示一个代码示例吗?这听起来越来越像是您想要来自 TPL 的实际Task。现在您的BotTask 没有与任何工作相关联,因此不清楚如何按照您的描述将这些嵌套。
  • 查看开始覆盖上的编辑,也许你会明白,如果没有,我们来聊聊。
【解决方案2】:

使运行集受保护而不是私有。这样它就不能从外部访问,但它可以被继承自 BotTask 的实体访问

【讨论】:

  • 抱歉,我不需要。请看编辑。我想从外部访问Running,只访问get,而不是set
  • @garryman 正如你目前实现的那样,你甚至不能从BotTask 类之外的get 它。听起来您应该将其更改为受保护但使用私人设置器。
  • 这就是我在编辑中所做的。无论如何检查另一个答案,看看我的评论,看看你能不能弄清楚
  • 有什么理由你不能做一个受保护的集合而不是私有集合?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-10-26
  • 2012-06-06
  • 1970-01-01
  • 2015-04-27
  • 1970-01-01
  • 1970-01-01
  • 2014-04-17
相关资源
最近更新 更多