5

Rozważmy następujący „wystrzel i zapomnij” przypadek użycia:Wyjątek przenoszenia ognia i zapomnieć o C# 5 (w .NET 4.5)

Dzwoniący prosi niektórych danych z mojej metody. Moja metoda sprawdza pamięć podręczną, aby sprawdzić, czy dane już tam są. Jeśli nie, pobiera go ze źródła i zapisuje w pamięci podręcznej. Osoba dzwoniąca nie musi czekać na pojawienie się buforowania przed uzyskaniem wyników, a metoda nie powinna uniemożliwiać wywołującemu uzyskania wyniku, jeśli buforowanie zakończy się niepowodzeniem. Co mam dziś wygląda tak:

public Foo GetFoo(string fooKey) 
{ 
    // look for Foo with fooKey in cache 
    // if Foo is not found, get Foo with fooKey from source 
    // and assign it to local variable myFoo 
    Task cacheTask 
      = Task.Run 
       (
        () => CacheFoo(myFoo)// fire-and-forget the caching of myFoo 
       ); 
    return myFoo; 
} 

Jeśli CacheFoo zgłasza wyjątek to idzie nie zauważony i ostatecznie (w .NET 4.5) to zostaje wchłonięty przez ramy. Wolałbym raczej zrobić ostatnie zdjęcie, aby samemu usunąć wyjątek, ale nie chcę blokować bieżącego wątku. Jaki jest najlepszy sposób na zrobienie tego?

Oto co próbowałem

try 
{ 
    ... 
    cacheTask.ContinueWith 
      (
       (e) => { 
         if (cacheTask.IsFaulted) 
          { 
          /* log cacheTask.Exception */; 
          } 
         } 
       , TaskContinuationOptions.OnlyOnFaulted 
      ); 
} 

Czy istnieje lepszy sposób? Czy potrzebuję instrukcji "if" na IsFaulted lub czy jest to zbędne, ponieważ już określiłem "OnlyOnFaulted"?

Wszelkie opinie/sugestie będą mile widziane.

+0

Byłoby miło, gdyby można oznaczyć zadanie jako fire-and-forget..so bez Wait/ContinueWith możliwe. A ponieważ w tym przypadku nie ma nikogo, kto mógłby poradzić sobie z tym wyjątkiem, powinien on zawiesić aplikację, aby mieć ładny plik zrzutu, w którym można oglądać lokalne zmienne i stertę w momencie, w którym wyjątek został zgłoszony ... – mmmmmmmm

Odpowiedz

7

Cztery rzeczy:

  • Nie, nie trzeba Task.IsFaulted property; oddzwanianie zostanie uruchomione tylko w przypadku błędu:
  • Nie musisz przechwytywać cacheTask; e w twoim oddzwonieniu jest tym samym zadaniem, więc równie dobrze możesz użyć tego. (Wtedy sam delegat może być stosowany do wszystkich zadań.)
  • Jeśli zawsze zalogowaniu w taki sam sposób, może chcesz napisać metodę rozszerzenia na zadanie ułatwiają zrobić to
  • jako alternatywą do dodawania obsługi, można rozważyć zapisanie się TaskScheduler.UnobservedTaskException rejestrowanie i prowadzenie tam
+0

Łał. To było szybkie. Dzięki Jon! –

+0

Nie mogłem zrozumieć. Czy jest jakaś różnica między .NET 4.0 i 4.5 w tym? I co to jest? –

+2

@ ГеннадийВанинНовосибирск: Tak, jest różnica, chociaż nie jestem pewien, czy ma to znaczenie. .NET 4.0 zabiłby cały proces, gdyby zadanie zostało zarzucone w sposób nieobserwowany. .NET 4.5 nie. –