2013-07-16 94 views
16

我正在使用庫提供的方法以...Async結尾,並返回Task。我將在命令行應用程序中使用它們。所以我需要同步調用它們很多。等待異步任務,但沒有在AggregateException中包裝異常

C#當然不允許在Main方法中調用這些方法,因爲您不能在Main方法上使用async修飾符。假設這是任務:

var task = datastore.Save(data); 

我發現了幾個解決方案,如:

Tasks.WaitAll(task); 
task.Wait(); 

但是所有這些總結拋出的異常的AggregateException我不希望這樣。我只想說task.Result,我期望拋出原始異常。

當我使用返回的方法Task<TResult>task.Result拋出AggregateException即使沒有設置任何延續任務。這是爲什麼發作?

我也曾經嘗試過,

task.RunSynchronously(); 

提示錯誤:

RunSynchronously may not be called on a task not bound to a delegate, such as the task returned from an asynchronous method.

,所以我想這是不是標記爲async方法。

對於在沒有異步上下文的控制檯應用程序中使用爲異步應用程序設計的庫的模式的任何想法?

回答

27

I am going to use these in a command line application. So I need to call them synchronously a lot.

不,你不知道。你在可以在控制檯應用程序中使用async - await,你只需要在最上面做一個異步同步轉換。你可以做到這一點通過使用Wait()

public static void Main() 
{ 
    MainAsync().Wait(); 
} 

public static async Task MainAsync() 
{ 
    var datastore = …; 
    await datastore.SaveAsync(); 
} 

通常情況下,結合awaitWait()是一個壞主意(這可能導致死鎖),但這裏是正確的解決方案。

請注意,如果SaveAsync()引發異常並且您未捕獲該異常,則將從Wait()重新排列爲AggregateException。但您可以將其作爲MainAsync()中的原始例外(因爲它不使用Wait())。

如果您確實想要直接拋出第一個異常,您可以執行類似await的操作:task.GetAwaiter().GetResult()。請注意,如果Task包含多個異常,則只會得到第一個異常(但同樣適用於await)。

When I use a method returning Task<TResult> , task.Result throws AggregateException even though there are no continuation tasks set. Why is this happening?

這與延續無關。單個Task可以表示多個操作,並且每個操作都可以引發異常。正因爲如此,Task方法始終拋出包裝在AggregateException的異常。

I also have tried task.RunSynchronously()

這沒有任何意義。 RunSynchronously()只能在使用Task構造函數創建的Task上使用。這不是這種情況,所以你不能使用它。從異步方法返回的Task始終已經啓動。

2

您可以創建一個虛擬Main

public static void Main() 
{ 
    MainAsync().Wait(); 
} 

public static async Task MainAsync() 
{ 
    try { 
     var result = await dataStore.Save(data); 
    } catch(ExceptionYouWantToCatch e) { 
     // handle it 
    } 
} 

而且,看到這樣的回答:https://stackoverflow.com/a/9212343/1529246