2016-11-17 132 views
4

我一直在使用.NET 4.6.1中的異步調用,我想知道正確的方式來拋出錯誤是從一個接口的實現者,期望一個異步方法,但實際上是同步的。例如:C#異步異常包裝

public interface ISomeInterface 
{ 
    Task ExecuteAsync(); 
} 

public class SomeClass : ISomeInterface 
{ 
    public Task ExecuteAsync() 
    { 
     return Task.FromException(new Exception()); 
    } 
} 

我發現Task.FromExceptionhere

所以這是.NET 4.6仍然看似建議包裝異常。不過,我可以只寫了下面的代碼:

public class SomeClass : ISomeInterface 
{ 
    public Task ExecuteAsync() 
    { 
     throw new Exception(); 
    } 
} 

當我使用try/catch塊稱爲第二個實現,客戶端抓住了Exception,我認爲就是爲什麼我們在第一時間使用Task.FromException,什麼更多的是它還包含了整個調用堆棧到原始異常(而方法一隻有一個堆棧跟蹤到客戶端的等待操作)。看來第二種方法更好,但似乎每個人都在使用方法一。由於async的實施變更,現在已經接近過時了,還是我缺少某些東西?

我也注意到在堆棧跟蹤中,async方法現在不會在調用之間引入任何附加幀。我假設這只是爲了簡化堆棧跟蹤?

回答

1

拋出錯誤的正確方法是來自接口的實現者,該接口需要異步方法但實際上是同步的。

正如您發現的那樣,您可以直接拋出異常或將異常放在返回的Task上。

注意觀察異常的地方,這並不改變:

var task = obj1.ExecuteAsync(); 
await task; 

如果異常,直接拋向,它的時候ExecuteAsync被拋出時調用。如果異常放置在返回的任務上,則在任務爲await ed時拋出異常。 大部分是的時候,任務是await ed之後​​立即調用該方法,但並不總是(例如在Task.WhenAll種情況下)。

使用異步(任務返回)API時,返回的任務表示方法的執行。 async - 實現的API總是在返回的任務上放置任何異常。所以,我會說任務返回API的期望是任務會收到異常。

boneheaded exceptions的情況下,您可以採用任何方式。由於異常表示代碼錯誤,因此在引發時無關緊要。例如,LINQ to Objects將會立即引發頭部異常,而不是枚舉返回的枚舉器時。

但是,對於所有其他類型的例外情況,他們肯定應該返回Task。就個人而言,我只是在返回的Task上放置所有例外。

+0

啊哈,明白了!謝謝你澄清斯蒂芬。 – Matt