20

kaybetmeden nasıl yeniden işlersiniz Delegate.DynamicInvoke kullanarak çağıran birçok yöntem var. Bu yöntemlerden bazıları veritabanı çağrıları yapar ve SqlException'u yakalama ve TargetInvocationException'u yakalama ve aslında neyin yanlış gittiğini bulmak için içlerinden avlanma yeteneğine sahip olmak isterim.Bir TargetInvocationException iç istisnasını yığın izleme

Ben rethrow için bu yöntemi kullanıyordu ama yığın izleme temizler:

try 
{ 
     return myDelegate.DynamicInvoke(args); 
} 
catch(TargetInvocationException ex) 
{ 
    Func<TargetInvocationException, Exception> getInner = null; 
    getInner = 
     delegate(TargetInvocationException e) 
     { 
     if (e.InnerException is TargetInvocationException) 
      return getInner((TargetInvocationException) e.InnerException); 

     return e.InnerException; 
     }; 

    Exception inner = getInner(ex); 
    inner.PreserveStackTrace(); 
    throw inner; 
} 

PreserveStackTrace yöntem başka bir yazı sayesinde yukarı sabit bir uzantısı yöntemidir (Ben aslında ne bilmiyorum) . Bununla birlikte, bu her iki iz korumak için görünmez:

public static void PreserveStackTrace(this Exception e) 
{ 
    var ctx = new StreamingContext(StreamingContextStates.CrossAppDomain); 
    var mgr = new ObjectManager(null, ctx); 
    var si = new SerializationInfo(e.GetType(), new FormatterConverter()); 

    e.GetObjectData(si, ctx); 
    mgr.RegisterObject(e, 1, si); 
    mgr.DoFixups(); 
} 

cevap

27

sadece onun yığın izini koruyarak bir iç özel durum atması istiyorsanız, böyle bir yöntem ile bunu yapabilirsiniz:

public static void Rethrow(this Exception ex) 
{ 
    typeof(Exception).GetMethod("PrepForRemoting", 
     BindingFlags.NonPublic | BindingFlags.Instance) 
     .Invoke(ex, new object[0]); 
    throw ex; 
} 

Bu teknik Rx tarafından kullanılan (ve onlar tarafından maruz kaldığı bir uzantı yöntemi olan Exception.PrepareForRethrow) ve aynı zamanda Async CTP tarafından otomatik temizleme sistemiyle (herkese açık bir API olmadan) kullanılır. Ancak bu tekniğin teknik olarak desteklenmediğini unutmayın. Umarım Microsoft, gelecekte bunun için resmi bir API ekleyecektir. Oy vermek isterseniz, Microsoft Connect'te has been opened öneri.

Güncelleme: Resmi bir API, .NET 4.5: ExceptionDispatchInfo'a eklenmiştir.

+0

Not için ilginç nokta: 4'te ExceptionDispatchInfo.5, 4.0 veya 4.5 hedeflemenize bağlı olarak istisnaları yeniden düzenlerken Rx'ten farklı çağrı yığınları gördüğünüz anlamına gelir. İşlenmemiş OnErrors, 4.5'i hedeflerken değil, 4.5'i hedeflerken orijinal yığın iziyle yeniden oluşturulacaktır. –

2

.NET'in istisnayı, yalnızca orijinal istisnayı bırakmak yerine TargetInvocationException ile neden kapattığını aklınızda bulundurmanız gerekir. Bunun için gerçekten iyi bir neden var, istisnanın gerçek sebebinin nereden geldiği belli değil. DynamicInvoke() çağrısı borked olduğu için miydi? Pek olası değil, derleyicinin doğru argümanların geçtiğinden emin olmak için yapabileceği hiçbir şey yok. Veya çağrılan hedef yöntemi tek başına mı attı?

Kural dışı durumun gerçek nedenini yargılamak için hem numaralı numaralı telefonu bilmeniz gerekir. TargetInvocationException'ı kasıtlı olarak gizlemek, DynamicInvoke() çağrısı ile ilgili bir sorun olsaydı, sorunun kaynağını bulmak için size sert sert bir zaman kazandıracak. Bunu yapmaktan kaçının.

+1

Akıl yürütmeyi takdir ediyorum ancak belirli hataları açık bir şekilde yakalamanın esnekliğinden dolayı tüketici kodu yazmayı zorlaştırıyor. –

+1

Bu senaryodaki istisnaları yakalamak, olağanüstü bir şekilde zordur. Delegenin hedefi hakkında hiçbir şey bilmiyorsunuz, programın durumunu nasıl değiştirdiğini tahmin edemezsiniz. Ve istisnai durumun üstesinden geldiğinizde durumu geri yükleyemezsiniz. –

+0

TIE'nin konuyla karıştırdığı bir durum, istisnayı atan “iç” kodun ve istisnaları işlemek isteyen dış kodun kontrolünü ele geçirmenizdir. İç kod, onu dinamik bir proxy içinde sarmalayan bir şey kullanarak enjekte edildiyse, artık iç koddan kendinizi atarken istisnaları yakalamak daha da zorlaşır. Bu, örneğin, varlık sınıflarının bir kısmının sarılabildiği, tercihen çevredeki kodun dikkat etmesi gerekmeyen ORM'ler ile olur. –

İlgili konular