2017-02-13 10 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() возвращается недействительным, и я использую возврат внутри, или если WriteSomeLines() задач и вывел следующую я возвращать нуль там? Я читал, что я не могу использовать await с недействительными методами возвращающихся, но вставив

await task; 

после объявления задач (в приведенном выше коды) компилирует прекрасно, и работает без проблем.

Edit:

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() возвращает недействительным.

Также, немного нереализованный, я правильно распоряжаюсь 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.

Вы можете использовать awaitв с async void метод, но вы не можете использовать await для потреблять в async void метод (потому что вы не awaitvoid может).

Я рекомендую вам ознакомиться с моим async intro blog post; это должно помочь вам лучше понять async и await.

Я ухожу из-за аннулированияTokenSource правильно здесь?

Ваша кнопка запуска должна отменить/удалить старый cts, когда он создает новый.