2013-07-16 13 views
16

Używam biblioteki, która udostępnia metody kończące się na ...Async i zwraca Task. Zamierzam je wykorzystać w aplikacji wiersza poleceń . Muszę więc nazywać je synchronicznie.Poczekaj na zadanie async bez wyjątków pakowania w wyjątku AggregateException

C# oczywiście nie zezwala na wywoływanie tych metod w metodzie Main, ponieważ nie można użyć modyfikatora async na metodzie Main. Zakładam, że to jest zadanie:

var task = datastore.Save(data); 

Znalazłem kilka rozwiązań takich jak:

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

jednak wszystkie te owinięcia rzucony wyjątków w AggregateException, nie chcę, że. Chcę tylko powiedzieć: task.Result i oczekuję, że oryginalny wyjątek zostanie zgłoszony.

Kiedy stosować metodę powracającego Task<TResult>, task.Result rzuca AggregateException chociaż istnieją żadne określone zadania uzupełniające. Dlaczego to się dzieje?

ja też próbowałem,

task.RunSynchronously(); 

daje błąd:

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

więc myślę, że nie jest dla metod oznaczonych jako async.

Wszelkie pomysły dotyczące wzorców z wykorzystaniem bibliotek zaprojektowanych dla aplikacji asynchronicznych w aplikacjach konsolowych, w których nie ma kontekstu asynchronicznego?

Odpowiedz

27

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

Nie, nie. Użytkownik może użyć async - await w aplikacji konsolowej, wystarczy ustawić asynchronizację, aby zsynchronizować przejście na samej górze. I można to zrobić za pomocą Wait():

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

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

Zazwyczaj łączenie await z Wait() jest zły pomysł (może to powodować zakleszczenia), ale jest to dobre rozwiązanie tutaj.

Pamiętaj, że jeśli SaveAsync() zgłasza wyjątek, a Ty go nie złapiesz, zostanie ponownie zgłoszony jako AggregateException z . Ale można go złapać jako oryginalny wyjątek w MainAsync() (ponieważ nie używa on Wait()).

Jeśli naprawdę chciałeś, aby pierwszy wyjątek został wygenerowany bezpośrednio, możesz zrobić coś podobnego do tego, co await: task.GetAwaiter().GetResult(). Zauważ, że jeśli Task zawiera więcej niż jeden wyjątek, otrzymasz tylko pierwszy (ale to samo dotyczy 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?

Nie ma to nic wspólnego z kontynuacją. Pojedynczy Task może reprezentować wiele operacji, a każdy z nich może wygenerować wyjątek. Z tego powodu, Task metody wyrzucać wyjątki opakowane w AggregateException.

I also have tried task.RunSynchronously()

To nie ma żadnego sensu. RunSynchronously() mogą być używane tylko na Task s, które zostały utworzone przy użyciu konstruktora Task. Tak nie jest w tym przypadku, więc nie możesz z niego korzystać. Task s zwrócone z metod asynchronicznych są zawsze już uruchomione.

2

Można utworzyć atrapę Main

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

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

również zobaczyć tę odpowiedź: https://stackoverflow.com/a/9212343/1529246

Powiązane problemy