2015-08-18 27 views
7

Task.Run'dan özel durumumu yakalamakla ilgili bir sorun yaşadım Kodumu değiştirdim ve sorunum çözüldü. Bu iki şekilde Task.Run içindeki özel durumları ele alma arasındaki farkın ne olduğunu bulmaya hazırım:Task.Run İstisnası Nasıl Kullanılır

Dış fonksiyonda bu özel durumu yakalayamıyorum, ancak İçinde bunu yakalayabiliyorum.

void Outside() 
{ 
    try 
    { 
     Task.Run(() => 
     { 
      int z = 0; 
      int x = 1/z; 
     }); 
    } 
    catch (Exception exception) 
    { 
     MessageBox.Show("Outside : " + exception.Message); 
    } 
} 

void Inside() 
{ 
    Task.Run(() => 
    { 
     try 
     { 
      int z = 0; 
      int x = 1/z; 
     } 
     catch (Exception exception) 
     { 
      MessageBox.Show("Inside : "+exception.Message); 
     } 
    }); 
} 

DÜZENLEME (Yinelenen Açıklama):

Ben await Task.Run(...) arayarak zaman uyumsuz olması tutucu işlevi ihtiyacı beri zaman uyumsuz benim İç ve dış fonksiyonlar olmak istemedim.

+1

Bkz. [Özel Durum İşleme (Görev Paralel Kitaplığı)] (https://msdn.microsoft.com/en-us/library/dd997415%28v=vs.110%29.aspx) –

+2

OP ise bu bir kopya değildir. "bekliyor" kullanmıyor ... Ve eğer .net 4.x kullanıyorsa, 'bekle' kullanamaz. –

+0

@MatthewWatson Emin misin? 'bekliyor'. NET 4.x! –

cevap

13

Bir görev çalıştırıldığında, bir görevin sonucu veya görevi tamamlamak için bir şey beklediğinde attığı tüm özel durumlar korunur ve yeniden atılır.

try 
{ 
    await Task.Run(...); 
    ... 

: Eğer await yerine ot Task.Wait (kullanabilirsiniz C#) yeni sürümleri için

var task = Task.Run(...) 

try 
{ 
    task.Wait(); // Rethrows any exception(s). 
    ... 

:

Task.Run() yüzden bunu yapmak için kullanabileceğiniz bir Task nesneyi döndürür çok daha fazla olanı. Birlikte UI anlaşma sağlayarak, bir hata sonra devam etmek benim Task.Run istediğini Benim için

using System; 
using System.Threading; 
using System.Threading.Tasks; 

namespace ConsoleApp1 
{ 
    class Program 
    { 
     static void Main() 
     { 
      test().Wait(); 
     } 

     static async Task test() 
     { 
      try 
      { 
       await Task.Run(() => throwsExceptionAfterOneSecond()); 
      } 

      catch (Exception e) 
      { 
       Console.WriteLine(e.Message); 
      } 
     } 

     static void throwsExceptionAfterOneSecond() 
     { 
      Thread.Sleep(1000); // Sleep is for illustration only. 
      throw new InvalidOperationException("Ooops"); 
     } 
    } 
} 
+1

gerektirdiğini söylemeliyim. Ayrıca' task.Result 'varsa, bir istisna atar. – VMAtm

+4

Daha yeni C# sürümleriyle bile, * Task.Wait() 'yerine' bekletme 'kullanmak mümkün değildir. [Beklemeden (C# Referansı)] (https://msdn.microsoft.com/en-us/library/hh156528%28v=vs.140%29.aspx) 'dan: "** beklemede olan eşzamansız yöntem ** kullanılan [async] (https://msdn.microsoft.com/en-us/library/hh156513.aspx) anahtar sözcüğü ile değiştirilmelidir. " – DavidRR

+0

var task = Görev.Run (...) ve task.Wait() işlevinden sonra çağrılar senkronize edilir, elbette tüm senkronizasyonlar gibi özel durum yakalanır. adında bir daha asla çağrılmayan görev bekle.Run (...) async çağrısı ve yine istisna yakalayamazsınız. ya da berbat ettim ... :) –

0

: Bütünlüğü için


, burada await kullanımını gösteren bir Derlenebilir konsol uygulaması var zaman olduğu gibi hata.

Benim (garip?) Çözümüm ayrıca bir Form.Timer çalıştırmaya sahip olmaktır. Benim Task.Run kuyruğu (uzun süre çalışan UI olmayan şeyler için) vardır ve benim Form.Timer sıra (UI şeyler için) vardır.

Bu yöntem zaten benim için çalışıyor olduğundan, hata işleme eklemek önemsizydi: task.Run bir hata alırsa, hata iletisini gösteren hata bilgisini Form.Timer kuyruğuna ekler.

3

Task.Wait'i kullanma fikri, hile yapacaktır, ancak çağrı iş parçacığının (kodun söylediği gibi) beklemesine neden olacak ve bu nedenle görev sonlandırılıncaya kadar engellenecek ve bu da kodu eşzamanlı olarak eşzamanlı olarak eşzamanlı hale getirecektir. Görev UI iş parçacığı devam etmek gerekiyorsa şöyle devam üzerindeki parametre olarak bize,

Task.Run(() => 
{ 
    //do some work 
}).ContinueWith((t) => 
{ 
    if (t.IsFaulted) throw t.Exception; 
    if (t.IsCompleted) //optionally do some work); 
}); 

TaskScheduler.FromCurrentSynchronizationContext() seçeneği:

yerine sonuçlara ulaşmak için Task.ContinueWith seçeneğini kullanın

).ContinueWith((t) => 
{ 
    if (t.IsFaulted) throw t.Exception; 
    if (t.IsCompleted) //optionally do some work); 
}, TaskScheduler.FromCurrentSynchronizationContext()); 

Bu kod, görev seviyesinden toplu istisnayı basitçe yeniden atayacaktır. Elbette, diğer bazı özel durum işleme yöntemlerini de tanıtabilirsiniz.

0

Dış kodunuzda, yalnızca bir görevin başlatılması görevinin gövdesinin kendisinin istisna atıp atmadığını kontrol edersiniz. Eşzamansız olarak çalışır ve bunu başlatan kod o zaman yapılır.

Sen kullanabilirsiniz:

void Outside() 
{ 
    try 
    { 
     Task.Run(() => 
     { 
      int z = 0; 
      int x = 1/z; 
     }).GetAwaiter().GetResult(); 
    } 
    catch (Exception exception) 
    { 
     MessageBox.Show("Outside : " + exception.Message); 
    } 
} 

görev biter ve oldukları gibi geçtiği istisna atılan ve AggregateException koymayı değil dek .GetAwaiter().GetResult() bekler kullanma.