C# Task.Factory.StartNew的包装器方法,用于执行具有不同参数和返回值的自定义方法

C# Task.Factory.StartNew的包装器方法,用于执行具有不同参数和返回值的自定义方法,c#,multithreading,task-parallel-library,task,cancellation-token,C#,Multithreading,Task Parallel Library,Task,Cancellation Token,我正在用.NET4.0在C中开发一个MDI应用程序。我创建了一个包装类TaskManager,以管理一些方法在不同任务上的执行 所以我可以打电话: _taskManager.StartNewTask(MethodName); 我需要在一个独立的任务中执行每一种紧张的工作方法 我创建这个包装类是为了避免调用散布在代码中的Task.Factory.StartNew(),从而保持它的整洁,并且能够以某种方式跟踪线程 我的问题是,现在我正在尝试取消任务,例如,如果用户按下ESC键,任务中止。为此,我需

我正在用.NET4.0C中开发一个MDI应用程序。我创建了一个包装类
TaskManager
,以管理一些方法在不同任务上的执行

所以我可以打电话:

_taskManager.StartNewTask(MethodName);
我需要在一个独立的
任务中执行每一种紧张的工作方法

我创建这个包装类是为了避免调用散布在代码中的
Task.Factory.StartNew()
,从而保持它的整洁,并且能够以某种方式跟踪线程

我的问题是,现在我正在尝试取消
任务
,例如,如果用户按下ESC键
任务
中止。为此,我需要使用
CancellationToken
,并将其作为参数添加到所有方法中。然后必须在每个方法体中检查它。例如:

private void MethodName(CancellationToken ct)
{
    // Verify cancellation request
    if (ct.IsCancellationRequested)
    {
        // Log the cancellation request "The task was cancelled before it got started"
        ct.ThrowIfCancellationRequested();
    }

    // Do the heavy work here
    // ...
    // At some critic point check again the cancellation request
    if (ct.IsCancellationRequested)
    {
        // Log the cancellation request "The task was cancelled while still running"
        ct.ThrowIfCancellationRequested();
    }
}
现在,我的
TaskManager.StartNewTask()
逻辑如下:

public int StartNewTask(Action method)
{
    try
    {
        CancellationToken ct = _cts.Token;
        Task task = Task.Factory.StartNew(method, ct);

        _tasksCount++;
        _tasksList.Add(task.Id, task);

        return task.Id;
    }
    catch (Exception ex)
    {
        _logger.Error("Cannot execute task.", ex);
    }

    return -1;
}
我想要的是:

  • 我需要更改
    TaskManager.StartNewTask()
    的逻辑,以便能够将CancellationToken传递给方法,但我不知道如何操作
  • 我还想知道是否有可能创建一个更通用的TaskManager.StartNewTask()
  • 方法,该方法可以使用任意数量的输入参数以及任何类型的返回值执行任何类型的方法 我需要这样的东西:

    // I don't know ho to change the method signature to accept
    // methods with parameters as parameter...
    public int StartNewTask(Action method)
    {
        try
        {
            CancellationToken ct = _cts.Token;
            // Here I need to pass the CancellationToken back to the method
            // I know that this can't be the way...
            Task task = Task.Factory.StartNew(method(ct), ct);
    
            _tasksCount++;
            _tasksList.Add(task.Id, task);
    
            return task.Id;
        }
        catch (Exception ex)
        {
            _logger.Error("Cannot execute task.", ex);
        }
    
        return -1;
    }
    
    更新1(针对问题2) (更改了自定义方法)

    如果我必须执行这样的方法

    int CustomMethod (int a, int b, CancellationToken ct)
    
    在使用我的
    TaskManager.StartNewTask()
    方法的新
    Task
    中,我应该如何更改
    StartNewTask()
    以及如何进行调用

    差不多

    int result = taskManager.StartNewTask(CustomMethod(<input parameters here>));
    
    int result=taskManager.StartNewTask(CustomMethod());
    
    代码可能是这样的

    public partial class MyForm : Form
    {
        private readonly TaskManager _taskManager;
    
        public MyForm()
        {
            InitializeComponent();
            _taskManager = TaskManager.GetInstance();
        }
    
        private void btnOK_Click(object sender, EventArgs e)
        {
            // This is the call to StartNewTask()
            // where now I need to set the parameters for CustomMethod()
    
            // Input parameters could be class variables or a custom object
            // with specific Properties such as:
            // MyObject.MyString, MyObject.MyDouble
            int result = _taskManager.StartNewTask(CustomMethod<input parameters here>);
    
            // Do something with my result...
            MessageBox.Show("Result: " + result, "Operation", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }
    
        private int CustomMethod(int a, int b, CancellationToken ct)
        {
            if (ct.IsCancellationRequested)
            {
                ct.ThrowIfCancellationRequested();
            }
    
            int result = -1;
    
            // Do some heavy work with int 'a', int 'b' and produce result...
            // Meanwhile check again for cancel request
    
            return a + b;
        }
    }
    
    公共部分类MyForm:Form
    {
    专用只读任务管理器_TaskManager;
    公共MyForm()
    {
    初始化组件();
    _taskManager=taskManager.GetInstance();
    }
    私有无效btnOK_单击(对象发送者,事件参数e)
    {
    //这是对StartNewTask()的调用
    //现在我需要设置CustomMethod()的参数
    //输入参数可以是类变量或自定义对象
    //具有特定属性,例如:
    //MyObject.MyString,MyObject.MyDouble
    int result=_taskManager.StartNewTask(CustomMethod);
    //对我的结果做点什么。。。
    MessageBox.Show(“结果:+结果,“操作”,MessageBoxButtons.OK,MessageBoxIcon.Information);
    }
    私有int CustomMethod(int a、int b、CancellationToken ct)
    {
    如果(ct.IsCancellationRequested)
    {
    ct.ThrowIfCancellationRequested();
    }
    int结果=-1;
    //用int'a',int'b做一些繁重的工作并产生结果。。。
    //同时再次检查取消请求
    返回a+b;
    }
    }
    
    更新2

    在尝试了@Sriram Sakthivel对我的问题2的建议后,我现在得到了以下代码:

    private void btnOK_Click(object sender, EventArgs e)
    {
        // a=1 and b=3
        int result = _taskManager.StartNewTask((ct) => CustomMethod(1, 3, ct));
        // On the MessageBox I get 2...
        MessageBox.Show("Result: " + result, "Operation", MessageBoxButtons.OK, MessageBoxIcon.Information);
    }
    
    private int CustomMethod(int a, int b, CancellationToken ct)
    {
        if (ct.IsCancellationRequested)
        {
            ct.ThrowIfCancellationRequested();
        }
    
        // a=1 and b=3, so the sum must me 4...
        return a + b;
    }
    
    public class TaskManager
    {
        private static readonly TaskManager Instance = new TaskManager();
        private readonly Dictionary<int, Task> _tasksList;
        private static int _tasksCount;
        private static CancellationTokenSource _cts;
    
        public int StartNewTask(Action<CancellationToken> method)
        {
            try
            {
                CancellationToken ct = _cts.Token;
                Task task = Task.Factory.StartNew(() => method, ct);
    
                _tasksCount++;
                _tasksList.Add(task.Id, task);
    
                return task.Id;
            }
            catch (Exception ex)
            {
                _logger.Error("Cannot execute the task.", ex);
            }
    
            return -1;
        }
    }
    
    private void btnOK_单击(对象发送者,事件参数e)
    {
    //a=1和b=3
    int result=_taskManager.StartNewTask((ct)=>CustomMethod(1,3,ct));
    //在消息框上我得到2。。。
    MessageBox.Show(“结果:+结果,“操作”,MessageBoxButtons.OK,MessageBoxIcon.Information);
    }
    私有int CustomMethod(int a、int b、CancellationToken ct)
    {
    如果(ct.IsCancellationRequested)
    {
    ct.ThrowIfCancellationRequested();
    }
    //a=1和b=3,所以总和必须等于4。。。
    返回a+b;
    }
    公共类任务管理器
    {
    私有静态只读TaskManager实例=新建TaskManager();
    专用只读词典_tasksList;
    专用静态int_taskscont;
    私有静态取消令牌源;
    public int StartNewTask(操作方法)
    {
    尝试
    {
    取消令牌ct=\u cts.Token;
    Task Task=Task.Factory.StartNew(()=>method,ct);
    _TaskScont++;
    _tasksList.Add(task.Id,task);
    返回task.Id;
    }
    捕获(例外情况除外)
    {
    _logger.Error(“无法执行任务”,例如);
    }
    返回-1;
    }
    }
    
    它让我回到2。。。但是a=1和b=3。。。所以总数应该是4


    它可能与
    TaskManager.StartNewTask()
    的返回类型有关。。。但是我应该如何管理在新任务中执行的方法的返回值呢?出什么事了?

    我想你只需要采取行动,除非我误解了

    public int StartNewTask(Action<CancellationToken> method)
    {
        try
        {
            CancellationToken ct = _cts.Token;
            Task task = Task.Factory.StartNew(method(ct), ct);
    
            _tasksCount++;
            _tasksList.Add(task.Id, task);
    
            return task.Id;
        }
        catch (Exception ex)
        {
            _logger.Error("Cannot execute task.", ex);
        }
    
        return -1;
    }
    

    问题1:是的,它有效!问题2:您能否更明确地说明“使用clousures访问方法周围环境”的含义?你能在你的答案中添加一个代码示例吗?假设我想用我的
    TaskManager.StartNewTask()方法执行一个
    int CustomMethod(字符串a,双b,CancellationToken ct)
    方法。如何更改我的
    StartNewTask()
    以及如何调用
    int return=taskManager.StartNewTask(CustomMethod())?@RainbowCoder我会更新我的帖子,但你打算如何传递参数,我对此一无所知。你从哪里得到这些任意参数?我已经更新了我的答案,看看是否有帮助。虽然没有经过测试,但我有一些奇怪的行为。。。我会更新问题的代码。看看你从
    开始的newtask
    方法返回了什么?返回的是
    TaskId
    ,而不是计算结果。要启用返回值,您需要
    Func
    而不是
    Action
    。是的,没错。但是现在,我如何管理任务Id的返回以及正在运行的方法的返回值呢
    int result = _taskManager.StartNewTask((ct)=> CustomMethod(paramA, paramB,ct));