Szorstki! Myślę, że to niemożliwe, ponieważ przebicie odpowiada specjalnej instrukcji IL, która chwyta wyjątek z góry stosu, ale sposób, w jaki wyrażenia asynchroniczne są zestawiane w łańcuch kontynuacji, nie sądzę, że semantyka będzie trwała!
Z tego samego powodu, co następuje nie zostanie skompilowany albo:
try
(null:string).ToString()
with e ->
(fun() -> reraise())()
W tych sytuacjach, w których muszę obsłużyć wyjątek poza rzeczywistą with
ciała, a chcieliby naśladować reraise
(czyli jest, zachować ślad stosu wyjątku), używam this rozwiązanie, więc wszyscy razem kod wyglądałby następująco:
let inline reraisePreserveStackTrace (e:Exception) =
let remoteStackTraceString = typeof<exn>.GetField("_remoteStackTraceString", BindingFlags.Instance ||| BindingFlags.NonPublic);
remoteStackTraceString.SetValue(e, e.StackTrace + Environment.NewLine);
raise e
let executeAsync context = async {
traceContext.Properties.Add("CorrelationId", context.CorrelationId)
try
do! runAsync context
return None
with
| e when isCriticalException(e) ->
logCriticalException e
reraisePreserveStackTrace e
| e ->
logException e
return Some(e)
}
Aktualizacja: .NET 4. 5 wprowadzono ExceptionDispatchInfo, co może pozwolić na czystszą implementację powyżej reraisePreserveStackTrace
.
Ta odpowiedź jest chyba nieaktualne. W .net 4.5 możesz użyć klasy 'ExceptionDispatchInfo', która robi to i przechwytuje informacje o wiadrze Watsona, takie jak zbiór pochodzenia i przesunięcie IL. http://msdn.microsoft.com/en-us/library/system.runtime.exceptionservices.exceptiondispatchinfo(v=vs.110).aspx –
@DaxFohl może dostarczyć zaktualizowaną odpowiedź za pomocą 'ExceptionDispatchInfo'? –