2017-05-14 46 views
0

我有一個應用程序被配置爲捕獲任何在app.config中ThrowUnobservedTaskExceptions enabled =「true」的未觀測任務異常。處理UnobservedTaskException

我有一個庫類(Class1)需要在它的構造函數中啓動一個異步任務,但是在某些引發異常的場景中,當Class1的實例被丟棄時我進入UnobservedTaskException錯誤(因爲那個任務永遠不會期待已久的)。

我解決了這個問題,通過在構造函數中附加ContinueWith並處理異常(通過訪問任務的Exception屬性),並將TaskContinuationOptions設置爲OnlyOnFaulted,並且完美地工作。

現在我遇到的問題是這個異步任務(我在構造函數中初始化)也在等待這個類的方法作爲驗證檢查,以確保任務完成後繼續執行方法中的其餘代碼。如果在實例化我的類(Class1)後調用了此方法,並且它引發了錯誤,則我已附加的ContinueWith會被執行並處理異常。我不想要這種行爲。如果在方法內部等待時發生錯誤,我希望它拋出異常。

我只希望unobservedtaskexceptions只針對這種情況處理(不針對整個應用程序) - 當Class1被初始化並且沒有方法被調用時,以及如果任務拋出異常,我會在ContinueWith中處理它。我不希望ContinueWith中的代碼在方法內等待此任務時執行,並且如果拋出。

下面是將提供更清晰的代碼。請讓我知道是否有辦法實現這一目標。

的Program.cs

using (Class1 c = new Class1()) 
{ 
     c.ValidateInitializeAsync().Wait(); // I want this to throw. Only if this line is commented, I want the exception to be handled. 
} 

// The application needs to be run in Release mode in order for GC to dispose c and enter into the scenario I want 
while (true) 
{ 
    Thread.Sleep(100); 
    GC.Collect(); 
    GC.WaitForPendingFinalizers(); 
} 

的Class1.cs

class Class1 : IDisposable 
{ 
    public Task initializeTask; 

    public Class1() 
    { 

     this.initializeTask = TaskHelper.InlineIfPossible(() => RunTask()).ContinueWith(t => 
     { 
      Console.WriteLine(string.Format("Exception handled, {0}", t.Exception.HResult)); 

     }, TaskContinuationOptions.OnlyOnFaulted); 
    } 

    public async Task ValidateInitializeAsync() 
    { 
     await this.initializeTask; 
    } 
    public async Task RunTask() 
    { 
     await Task.Run(() => 
     { 
      Console.WriteLine("Running task..."); 
      Task.Delay(5000).Wait(); 
      throw new InvalidOperationException("exception occured"); 
     }); 
    } 

    public void Dispose() 
    { 
     Console.WriteLine("Class1 disposed."); 
    } 
} 

static class TaskHelper 
{ 
    static public Task InlineIfPossible(Func<Task> function) 
    { 
     if (SynchronizationContext.Current == null) 
     { 
      return function(); 
     } 
     else 
     { 
      return Task.Run(function); 
     } 
    } 
} 

回答

0

什麼你問的是不可能的。考慮一下隨着時間的推移:當RunTask完成並出現異常時,代碼必須知道然後是否處理該異常。它不能展望未來,並確定將由await處理爲

我推薦使用async factory pattern,以便在調用代碼甚至獲取實例之前立即傳播任何初始化異常。