考虑一个带有 2 个按钮和一个富文本框的表单:
public partial class MainForm : Form
{
CancellationTokenSource cts;
CancellationToken token;
public MainForm()
{
InitializeComponent();
}
private void MainForm_Load(object sender, EventArgs e)
{
cts = new CancellationTokenSource();
token = cts.Token;
var task = Task.Run(() => WriteSomeLines(), token);
}
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
cts.Dispose();
}
private void btnStart_Click(object sender, EventArgs e)
{
cts = new CancellationTokenSource();
token = cts.Token;
var task = Task.Run(() => WriteSomeLines(), token);
}
private void btnCancel_Click(object sender, EventArgs e)
{
try
{
cts.Cancel();
cts.Dispose();
}
catch (ObjectDisposedException exc)
{
MessageBox.Show(exc.GetType().Name);
//object disposed
}
}
public void WriteSomeLines()
{
if (ControlInvokeRequired(rtbLoops, () => rtbLoops.Text += "Starting new loop \r\n")) ;
else rtbLoops.Text += "Starting new loop \r\n";
for (int i = 0; i < 30; i++)
{
try
{
if (ControlInvokeRequired(rtbLoops, () => { rtbLoops.AppendText("New line " + i + "\r\n"); rtbLoops.ScrollToCaret(); })) ;
else rtbLoops.AppendText("New line " + i + "\r\n");
Thread.Sleep(250);
token.ThrowIfCancellationRequested();
}
catch (OperationCanceledException ae)
{
MessageBox.Show(ae.GetType().Name);
return;
}
}
return;
}
public bool ControlInvokeRequired(Control c, Action a)
{
if (c.InvokeRequired)
c.Invoke(new MethodInvoker(delegate { a(); }));
else
return false;
return true;
}
}
如果 WriteSomeLines()
返回 void 而我在内部使用 return,或者如果 WriteSomeLines()
返回 Task 而我在那里返回 null,是否有区别?我读到我不能将 await
与 void 返回方法一起使用,而是插入
await task;
在任务声明之后(在上面的代码中)编译得很好,并且运行没有问题。
编辑:
private async void btnStart_Click(object sender, EventArgs e)
{
cts = new CancellationTokenSource();
token = cts.Token;
var task = Task.Run(() => WriteSomeLines(), token);
await task;
rtbLoops.Text += "Task complete";
}
如果 WriteSomeLines()
返回 void,则编译没有问题。
另外,有点不真实,我在这里正确地处理了 CancellationTokenSource
吗?
第二次编辑:
那么这是正确的方法吗:
private async void btnStart_Click(object sender, EventArgs e)
{
cts.Dispose();
cts = new CancellationTokenSource();
token = cts.Token;
var task = Task.Run(() => WriteSomeLines(), token);
bool result = await task;
if(result == true) rtbLoops.Text += "Task complete \r\n";
}
和
public async Task<bool> WriteSomeLines()
{
if (ControlInvokeRequired(rtbLoops, () => rtbLoops.Text += "Starting new loop \r\n")) ;
else rtbLoops.Text += "Starting new loop \r\n";
for (int i = 0; i < 30; i++)
{
try
{
if (ControlInvokeRequired(rtbLoops, () => { rtbLoops.AppendText("New line " + i + "\r\n"); rtbLoops.ScrollToCaret(); })) ;
else rtbLoops.AppendText("New line " + i + "\r\n");
await Task.Delay(250);
token.ThrowIfCancellationRequested();
}
catch (OperationCanceledException ae)
{
MessageBox.Show(ae.GetType().Name);
return false;
}
}
return true;
最佳答案
你不应该返回一个空任务;这应该会导致运行时 NullReferenceException
错误。
您可以在 async void
方法中使用 await
,但不能将 await
用于使用 async void
方法(因为你不能await
void
)。
我建议您查看我的 async
intro blog post ;它应该可以帮助您更好地理解 async
和 await
。
am I disposing CancellationTokenSource correctly here?
您的开始按钮在创建新的 cts
时需要取消/处置旧的 cts
。
关于c# - Task.Run a void 方法和 Task 方法返回 null 有区别吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42204954/