2017-02-13 64 views
3

考虑,2个按钮的表单和一个RichTextBox:与Task.Run有什么区别,void方法和Task方法返回null?

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我用回里面,或者如果WriteSomeLines()返回的任务,我也返回null呢?我看,我不能空回来方法使用await,但是任务宣布后插入

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; 

回答

4

你不应该返回一个空任务;这应该会导致运行时NullReferenceException错误。

可以内的async void方法使用await,但await消耗async void方法不能使用(因为你不能awaitvoid)。

我建议您查看我的async intro blog post;它应该有助于您更好地了解asyncawait

我在这里正确处理CancellationTokenSource?

您的开始按钮需要在创建新的按钮时取消/配置旧的cts

相关问题