我正在使用.NET 4.0在C#中开发MDI应用程序。我创建了一个包装类来管理不同任务上某些方法的执行。TaskManager
所以我可以打电话:
_taskManager.StartNewTask(MethodName);
我需要在一个单独的Task
.
我创建了这个包装类来避免调用Task.Factory.StartNew()
分散在代码周围的代码,从而保持它的干净,并且能够以某种方式跟踪线程。
我的问题是现在我正在尝试实现取消Task
,例如如果用户按ESC键Task
中止。为此,我需要使用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(针对问题 n.2) (更改了 CustomMethod)
如果我必须执行类似的方法
int CustomMethod (int a, int b, CancellationToken ct)
在Task
使用我的TaskManager.StartNewTask()
方法的新方法中,我应该如何更改StartNewTask()
以及如何拨打电话?
就像是
int result = taskManager.StartNewTask(CustomMethod(<input parameters here>));
代码可能是这样的
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;
}
}
更新 2
在为我的问题 2 尝试了@Sriram Sakthivel 建议后,我现在有了以下代码:
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;
}
}
它让我回到 2... 但是 a = 1 和 b = 3... 所以总和应该是 4!
它可能与TaskManager.StartNewTask()
...的返回类型有关。但是我应该如何管理我在新任务中执行的方法的返回值?怎么了?