2017-02-13 7 views
3

は2つのボタンとリッチテキストボックスでフォームを考えてみましょう:WriteSomeLines()はvoidを返すされており、私は内部のリターンを使用するか、またはWriteSomeLines()戻っタスクと私はそこにnullを返しない場合場合Task.Runとvoidメソッドとの違いはありますか?nullを返すTaskメソッドはありますか?

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; 
    }  
} 

は違いはありますか?私はvoidを返すメソッドで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()戻り、ボイド場合、これは問題なくコンパイルされます。

また、若干現れていませんが、私は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

あなたがnullタスクを返すことは決してありません。実行時にNullReferenceExceptionエラーが発生するはずです。

あなたはasync voidメソッド内awaitを使用することができますが、async void方法を消費awaitに、あなたは(なぜなら、あなたすることはできませんawaitvoid)を使用することはできません。

私はasync intro blog postを確認することをお勧めします。 asyncawaitをよりよく理解するのに役立ちます。

私はここでCancellationTokenSourceを正しく処分しますか?

新しいボタンを作成するときに、スタートボタンをキャンセル/廃棄する必要があります(cts)。

関連する問題