2011-06-16 18 views
8

Bu örnek "başarısız":Try-Catch zaman uyumsuz İstisnalar

olduğunu
static async void Main(string[] args) 
{ 
    try 
    { 
     await TaskEx.Run(() => { throw new Exception("failure"); }); 
    } 
    catch (Exception) 
    { 
     throw new Exception("success"); 
    } 
} 

, metni "başarısızlık" ile istisna kadar kabarcıklar.

static async void Main(string[] args) 
{ 
    try 
    { 
     await SafeRun(() => { throw new Exception("failure"); }); 
    } 
    catch (Exception) 
    { 
     throw new Exception("success"); 
    } 
} 

static async Task SafeRun(Action action) 
{ 
    var ex = default(Exception); 
    await TaskEx.Run(() => 
    { 
     try 
     { 
      action(); 
     } 
     catch (Exception _) 
     { 
      ex = _; 
     } 
    }); 
    if (ex != default(Exception)) 
     throw ex; 
} 

ya da yardım etmedi:

Sonra bu geçici çözümü çalıştı.

Async CTP yenileme kurulumumun askıya alınabileceğini varsayalım.

Bu kod beklediğim gibi çalışırsa ("başarı", "başarısızlık" artar) veya bu şekilde çalışmak için "varsayılan" olmaz. Ve eğer değilse, nasıl çalışırsın?

cevap

5

Gördüğünüz davranış, büyük olasılıkla bir büyük/küçük harf hatasıdır veya sorun çıkarsa bile doğru olabilir. Normal olarak eşzamansız bir senkronizasyon yöntemini çağırdığınızda, yürütmek üzere bir görevi tamamlar ve görevi bitirmek için bekleyen kimse olmadığından, istisna onu ana iş parçacığına dönüştürmez. Eğer doğrudan Main olarak adlandırılacak olsaydınız başarılı olurdu, ama sonra çalışma zamanınız başka bir iş parçacığında "başarı" istisnası görecekti.

Ana, uygulamanızın giriş noktası olduğu için, giriş noktası, Görev sarma davranışını tetiklemediği için eşzamanlı olarak ve olası bir şekilde çağrıldığından, beklemeye almadığı için TaskEx.Run kendi iş parçacığına atılır. Başka bir iş parçacığına atılan bir özel durum olarak çalışma zamanında gösterir.

Eğer dönen yani bir async yöntemi olarak ana çalıştırmak olsaydı bir Task ve senkron ana bağlamdan üzerinde engelleme (void sadece gerçekten await aracılığıyla çağrılabilir döndüren bir async beri), uygun davranışı alacağı Aşağıdaki test, aşağıdaki gibi göstermektedir:

static async Task Main() { 
    try { 
     await TaskEx.Run(() => { throw new Exception("failure"); }); 
    } catch(Exception) { 
     throw new Exception("success"); 
    } 
} 

static async Task Main2() { 
    await Main(); 
} 

[Test] 
public void CallViaAwait() { 
    var t = Main2(); 
    try { 
     t.Wait(); 
     Assert.Fail("didn't throw"); 
    } catch(AggregateException e) { 
     Assert.AreEqual("success",e.InnerException.Message); 
    } 
    } 


[Test] 
public void CallDirectly() { 
    var t = Main(); 
    try { 
     t.Wait(); 
     Assert.Fail("didn't throw"); 
    } catch(AggregateException e) { 
     Assert.AreEqual("success", e.InnerException.Message); 
    } 
} 

Ie Görev, iç istisna olarak başarı başarısını içeren AggregateException ile hata oluşturur.

+0

Bu, uyumsuzluk sınamak için bir konsol uygulamasından geliyor, bu yüzden benim durumumda en üst düzey yöntem Ana yöntemdir. –

+0

@Ben cevabı, bir hata olabileceği veya olmayabileceği, ancak bir "eşzamansız" giriş noktasının tanımlanamayan davranışından kaynaklandığına dair cevabı güncelledim. –