2013-07-22 10 views
5

Tworzę harmonogram zadań, więc staram się zrobić jakąś funkcję, która przyjmuje zadanie i czeka go powtarzać, ale pojawia się dziwny wyjątkiem Type 'T' is not awaitabletypu „T” nie jest awaitable

public static Task<T> Interval<T>(TimeSpan pollInterval, Func<T> action, CancellationToken token) 
{ 
    return Task.Factory.StartNew(
     async() => 
     { 
      for (; ;) 
      { 
       if (token.WaitCancellationRequested(pollInterval)) 
        break; 

       await action(); 
      } 
     }, token, TaskCreationOptions.LongRunning, TaskScheduler.Default); 
} 

więc można ktoś mi powiedzieć, jak mogę oczekiwać, że ogólne zadanie, bo chcę funkcja do zaakceptowania dowolnego zadania, zadania, bool lub dowolnego innego typu?

+1

Dlaczego 'Odstęp czasu' zwraca' Zadanie '? Nigdy się nie kończy (trwa tak długo, aż pojawi się wyjątek lub błędy) i nigdy nie ma wartości "T", która jest ustawiona jako wynik. – Servy

+0

@Servy nie mam token anulowania –

+1

Tak, a jeśli jest anulowane, to zadanie jest ustawione na anulowane. Nadal nie ma * wyniku *. W pewnym momencie jest on zakończony, ale nigdy nie ma "wyniku", który można pobrać. moim celem jest zwrócenie 'Task', a nie' Task 'i powinieneś zaakceptować' Action' zamiast 'Func ', ponieważ odrzucasz wynik działania. – Servy

Odpowiedz

8

Nie trzeba rozpocząć długą zadanie wydajność dla tego - po prostu zrobić swoje metody asynchronicznego bezpośrednio:

public static async Task RunAtIntervalAsync(TimeSpan pollInterval, Action action, CancellationToken token) 
{ 
    while(true) 
    { 
     await Task.Delay(pollInterval, token); 
     action(); 
    } 
} 

To spowoduje Action do uruchomienia na bieżącym kontekście. Jeśli nie jest to wymagane, można użyć:

await Task.Delay(pollInterval, token).ConfigureAwait(false); 
action(); 

To spowoduje Action aby nie działać na tym samym kontekście synchronizacji rozmówcy i potencjalnie użyć wątku puli wątków.


Edycja w odpowiedzi na komentarze:

Jeśli nie chcesz wynikowy zadanie wrócić odwołany, ale po prostu wrócić, gdy znacznik jest zwolniony, można użyć:

public static async Task RunAtIntervalAsync(TimeSpan pollInterval, Action action, CancellationToken token) 
{ 
    while(!token.IsCancellationRequested) 
    { 
     try 
     { 
      await Task.Delay(pollInterval, token); 
      action(); 
     } 
     catch(OperationCanceledException e) 
     { 
      // Swallow cancellation - dangerous if action() throws this, though.... 
      break; 
     } 
    } 
} 

Edit 2:

Jeśli chcesz przekazać w async lambdas, należy dokonać metoda wziąć Func<Task> nie Action:

public static async Task RunAtIntervalAsync(TimeSpan pollInterval, Func<Task> actionTask, CancellationToken token) 
{ 
    while(!token.IsCancellationRequested) 
    { 
     try 
     { 
      await Task.Delay(pollInterval, token); 
     } 
     catch(OperationCanceledException e) 
     { 
      // Swallow cancellation 
      break; 
     } 

     await actionTask(); 
    } 
} 

Edycja w odpowiedzi na czat:

Jeśli chcesz sondować, ale wykorzystać wyniki operacji, można użyć:

public static async Task RunAtIntervalAsync<T>(TimeSpan pollInterval, Func<Task<T>> fetchOperation, Action<T> operationOnResult, CancellationToken token) 
{ 
    while(!token.IsCancellationRequested) 
    { 
     try 
     { 
      await Task.Delay(pollInterval, token); 
     } 
     catch(OperationCanceledException e) 
     { 
      // Swallow cancellation 
      break; 
     } 

     // Get a value 
     T value = await fetchOperation(); 

     // Use result (ie: update UI) 
     operationOnResult(value); 
    } 
} 

następnie można nazwać to poprzez:

RunAtIntervalAsync(TimeSpan.FromSeconds(1), 
    async() => { await Task.Delay(1000); return "Foo"; }, 
    result => UpdateUI(result), 
    token); 
+0

klasa statyczna AnulowanieTokenExtensions { public static bool WaitCancellationRequested (ten token token przedziału czasu, Time Time Timeout) { return token.WaitHandle.WaitOne (timeout); } } –

+0

dobrze mogę po prostu włączyć (true) podczas (! Token.WaitCancellationRequested (pollInterval)) –

+0

@RuneS To jest blokowanie. Powyższe jest całkowicie asynchroniczne (nieblokujące). –

5

Nie możesz.

Można zrobić funkcję, która pobiera rodzajowe asynchroniczny funkcję – funkcję, która zwraca Task<T>. To jest Func<Task<T>>.

Można również utworzyć funkcję, która ma funkcję podstawową synchroniczną, która jest teraz dostępna.

Nie można wykonać jednej funkcji, która może zająć, ale można wykonać dwa przeciążenia.


W przypadku niepowiązanej notatki funkcja nigdy nie korzysta z wartości zwracanej przez funkcję.
Dlatego nie powinieneś generalizować go w ogóle; powinieneś zamiast tego wziąć Func<Task> lub Action.

+1

Czy możesz udzielić bardziej szczegółowej odpowiedzi, umieszczając fragmenty kodu lub po prostu bardziej czytelnie, ponieważ nie mogę Cię zrozumieć? –

+0

@RuneS: Której części nie rozumiesz? – SLaks

+0

To, co chcę zrobić wyraźnie, polega na tym, że w tej funkcji uzyskuję godną zaufania metodę, którą należy powtarzać, dopóki nie anuluję jej przez token anulowania ... więc wyobraź sobie, że mam zadanie, które zwraca wartość zamiast pustki. –

0

Sprawdź przykład tutaj: post. Zgadzam się z SLaksami, musisz zrobić ogólny parametr T Func, na który możesz czekać. Na przykład, jeśli T jest string, kod będzie "czekać" na funkcję, która zwraca tylko string. The await jest ważna tylko dla zadań. Aby uzyskać więcej informacji, sprawdź to wyjaśnienie: MSDN Blog; przykład jest w VB.net.