5

考慮下面的「發射後不管」的用例:異常處理火災和忘記C#5(在.NET 4.5)

呼叫者從我的方法要求一些數據。我的方法檢查緩存以查看數據是否已經存在。如果不是,它從源中提取並緩存它。調用者在得到他的結果之前不需要等待緩存發生,並且如果緩存發生故障,該方法不應該阻止調用者獲得結果。我今天有什麼,看起來是這樣的:

public Foo GetFoo(string fooKey) 
{ 
    // look for Foo with fooKey in cache 
    // if Foo is not found, get Foo with fooKey from source 
    // and assign it to local variable myFoo 
    Task cacheTask 
      = Task.Run 
       (
        () => CacheFoo(myFoo)// fire-and-forget the caching of myFoo 
       ); 
    return myFoo; 
} 

如果CacheFoo拋出它去不可觀測,最終的異常(在.NET 4.5),它被由框架吞沒。我寧願自己清理異常,但我不想阻止當前線程。什麼是最好的方式來做到這一點?

這裏是我試過

try 
{ 
    ... 
    cacheTask.ContinueWith 
      (
       (e) => { 
         if (cacheTask.IsFaulted) 
          { 
          /* log cacheTask.Exception */; 
          } 
         } 
       , TaskContinuationOptions.OnlyOnFaulted 
      ); 
} 

有沒有更好的辦法?我是否需要IsFaulted上的「if」聲明或者是否已經指定了「OnlyOnFaulted」?

任何意見/建議將不勝感激。

+0

將是很好,如果能任務標記爲火和forget..so沒有等待/ ContinueWith可能。因爲在這種情況下,沒有人可以處理異常,所以應用程序會崩潰,所以你有一個很好的轉儲文件,你可以在你的本地變量和堆中看到異常被拋出的時間點... – mmmmmmmm 2013-10-07 10:08:42

回答

7

四件事情:

  • 不,你不需要Task.IsFaulted property;回調只會在發生故障時觸發
  • 您無需捕獲cacheTask;回調中的e是相同的任務,所以您不妨使用它。 (然後相同的委託可用於所有任務。)
  • 如果你總是以同樣的方式登錄,您可能需要寫一篇關於任務的擴展方法,可以很容易做到這一點
  • 作爲還加入了處理器的選擇,你可以考慮訂閱TaskScheduler.UnobservedTaskException並有執行日誌
+0

哇。那很快。謝謝喬恩! – 2013-04-11 16:17:01

+0

我無法理解。 .NET 4.0和4.5之間有什麼區別嗎?還有,這是什麼? – 2013-04-12 11:26:40

+2

@ГеннадийВанинНовосибирск:是的,這裏有區別,雖然我不確定它在這裏有關。如果某個任務以不可觀察的方式發生故障,.NET 4.0將會終止整個過程。 .NET 4.5沒有。 – 2013-04-12 13:00:14