2012-11-17 50 views
4

我試圖實現自定義awaiteable執行await Thread.SleepAsync()沒有創建任何額外的線程。如何在c#中創建和使用自定義Awaitable?

下面是我得到了什麼:

class AwaitableThread : INotifyCompletion 
    { 
     public AwaitableThread(long milliseconds) 
     { 
      var timer = new Timer(obj => { IsCompleted = true; }, null, milliseconds, Timeout.Infinite); 
     } 

     private bool isCompleted = false; 

     public bool IsCompleted 
     { 
      get { return isCompleted; } 
      set { isCompleted = value; } 
     } 

     public void GetResult() 
     {} 

     public AwaitableThread GetAwaiter() { return this; } 

     public void OnCompleted(Action continuation) 
     { 
      if (continuation != null) 
      { 
       continuation(); 
      } 
     } 
    } 

而這裏的睡眠將如何工作:

static async Task Sleep(int milliseconds) 
    { 
     await new AwaitableThread(milliseconds); 
    } 

的問題是,這個函數返回immidiatly,即使在OnCompletedIsCompleted仍假。

我在做什麼錯?

+3

爲什麼不使用我在上一個問題上給出的答案? Task.Delay'正是你想要的。 (它立即完成的原因是順便說明你的OnCompleted方法做錯了什麼。) –

+0

我已經將它標記爲正確的答案,但現在我仍然對這些東西是如何工作並且可以是好奇的擴展 –

+1

如果你想了解'async'內部,最好的資源是[Jon Skeet的eduasync系列](http://msmvps.com/blogs/jon_skeet/archive/tags/Eduasync/default.aspx)。 –

回答

10

全面實施等待生產使用模式是一件棘手的業務 - 您需要捕獲執行上下文等等。 Stephen Toub's blog post對此有更多的細節。在許多情況下,更容易捎帶到Task<T>Task,可能使用TaskCompletionSource。例如,你的情況,你可以寫的Task.Delay這樣的等價物:

public Task MyDelay(int milliseconds) 
{ 
    // There's only a generic TaskCompletionSource, but we don't really 
    // care about the result. Just use int as a reasonably cheap version. 
    var tcs = new TaskCompletionSource<int>(); 

    Timer timer = new Timer(_ => tcs.SetResult(0), null, milliseconds, 
          Timeout.Infinite); 
    // Capture the timer variable so that the timer can't be garbage collected 
    // unless the task is (in which case it doesn't matter). 
    tcs.Task.ContinueWith(task => timer = null); 

    return tcs.Task; 
} 

現在,您可以await該任務,就像你可以等待的Task.Delay結果。

相關問題