2014-12-17 25 views
8

Czy ktoś mógłby wyjaśnić różnicę między tymi dwoma stwierdzeniami:Jak mogę produkować zadanie <Task> do otwierania

Task<Task> bTask = backup.BackupCurrentDatabaseAsync() 
    .ContinueWith(_ => CompressArchiveAsync()); 
//unwrap the tasks to produce one entire task 
Task t = bTask.Unwrap(); 

vs

Task<Task> bTask = backup.BackupCurrentDatabaseAsync() 
    .ContinueWith(_ => 
{ 
    CompressArchiveAsync(); 
}); 
//unwrap the tasks to produce one entire task 
Task t = bTask.Unwrap(); 

Metody ExtractArchiveAsync(), BackupCurrentDatabaseAsync(), RestoreDatabaseAsync() wszyscy zwracają Task.

Tutaj pierwsza kontynuacja zwraca wartość Task<Task>. Mogę wtedy wykonać zadanie Kontynuacja wypadkowego (wewnętrznego) zadania.

Druga wersja nie jest kompilowana. Jedyną różnicą jest tu nawias wokół urządzenia CompressArchiveAsync().

Próbuję uzyskać dostęp do wypadkowej (wewnętrznej) Task, aby sprawdzić Task.Status. Jeśli używam drugiej metody, Task.Status raportuje wynik zadania BackupCurrentDatabaseAsync().

+0

Side UWAGA: rozważyć przeniesienie do 4,5 i async/awiat, jeśli to możliwe ... Wytworzy łatwiejszy do odczytania kod ... –

+0

Niestety nadal na 4! Jak powyższe byłoby osiągnąć w 4,5? – Simon

+0

'async' /' await' jest głównym elementem C# 5.0. Chociaż działa tylko po wyjęciu z pudełka podczas kierowania na platformę .NET 4.5, możesz użyć pakietu kierowania asynchronicznego, aby [przenieść go do .NET 4.0] (http://stackoverflow.com/questions/9110472/using-async-await-on -net-4). – CodesInChaos

Odpowiedz

11
.ContinueWith(_ => CompressArchiveAsync()); 

odpowiada:

.ContinueWith(_ => 
{ 
    return CompressArchiveAsync(); 
}); 

obwieszczeniu return.

Twój drugi fragment kodu nie kompiluje się, ponieważ ContinueWith nie zwraca wartości Task<Task>, ale po prostu jest to Task i nie ma niczego do rozwinięcia.

jest związany z Func<Task, Task> (a funkcję, która pobiera i zwraca TaskTask)

_ => 
{ 
    return CompressArchiveAsync(); 
} 

Ale co następuje faktycznie związany do Action<Task> (funkcja, że ​​trwa Task ale nie po powrót cokolwiek):

_ => 
{ 
    CompressArchiveAsync(); 
} 

i odniesienie do Task stworzonej przez CompressArchiveAsync nigdy nie jest zwracana. Bez odniesienia do niego nie można sprawdzić stanu Task.

zauważyć, że:

Dlatego twoi ContinueWith(Func<Task, Task>) Zwraca Task<Task> które można rozpakować, ale twój ContinueWith(Action<Task>) prostu zwraca Task.

3

Różnica polega na składni Lambda Expression.

Istnieją 2 typy lambda: Ekspresja lambda i komunikat lambda. Wyrażenie Lambdas nie ma nawiasów klamrowych i zwraca wynik wyrażenia, podczas gdy Statement Lambdas ma nawiasy klamrowe zawierające zero lub więcej instrukcji (jednym z nich może być instrukcja return).

Więc to wyrażenie lambda:

_ => CompressArchiveAsync() 

jest równoznaczne z niniejszym Oświadczeniu Lambda:

_ => { return CompressArchiveAsync(); } 

Tak, różnica jest taka, że ​​w pierwszym kontynuacji wracasz zadanie, ale w drugim ty nie, to po prostu nieważny anonimowy delegat. Dlatego pierwszą kontynuacją jest Task<Task>, podczas gdy druga to tylko Task.

1

W pierwszym przykładzie wywołuje się ContinueWith z Func. Dlatego zwróci wartość Task<T>. Druga próba wywoła przeciążenie ContinueWith z Action, ponieważ ... cóż, to działanie, nic nie zwraca. Więc zwróci prosty Task bez T.

2

Długi komentarz, aby pokazać kod 4.5.

Gdybyś mógł przenieść się do .NET 4.5 niż kod, który próbujesz pisać może być zapisane w bardziej zwarty sposób z asynchroniczny/Oczekujcie która jest zasadniczo realizuje cały ten kod wewnętrzne:

async Task CompleteBackup() 
{ 
    await backup.BackupCurrentDatabaseAsync() 
    await CompressArchiveAsync()); 
    await ..... 
} 
+0

Dzięki Alexei, czy mam 'TaskContinuationOptions' powiązane z moimi' ContinueWith() ', czy ta metoda byłaby bardziej szczegółowa? – Simon

+0

@Simon Jeśli potrzebujesz bardzo szczegółowej kontroli nad zadaniami, prawdopodobnie będziesz nadal musiał używać 'ContinueWith' i podobnych połączeń bezpośrednio. Nie zrobiłem tego, więc nie mam żadnej bezpośredniej porady. –

+0

@Simon: Polecam użyć tego 'opartego na oczekiwaniu 'kodu. Można go używać z pulpitem .NET 4.0, instalując pakiet [Microsoft.Bcl.Async] (https://www.nuget.org/packages/Microsoft.Bcl.Async/). Z 'await', wszystkie odpowiednie' TaskContinuationOptions' są już dostarczone i nie ma potrzeby, aby poziom kontroli. –

Powiązane problemy