Asynchronous 如何在F#中的异步工作流中使用reraise?
我需要在记录异常后,重新释放在执行异步块时发生的异常 当我执行以下操作时,编译器认为我没有从处理程序中调用reraise函数。我做错了什么Asynchronous 如何在F#中的异步工作流中使用reraise?,asynchronous,exception-handling,f#,f#-async,Asynchronous,Exception Handling,F#,F# Async,我需要在记录异常后,重新释放在执行异步块时发生的异常 当我执行以下操作时,编译器认为我没有从处理程序中调用reraise函数。我做错了什么 let executeAsync context = async { traceContext.Properties.Add("CorrelationId", context.CorrelationId) try do! runAsync context return None with
let executeAsync context = async {
traceContext.Properties.Add("CorrelationId", context.CorrelationId)
try
do! runAsync context
return None
with
| e when isCriticalException(e) ->
logCriticalException e
reraise()
| e ->
logException e
return Some(e)
}
粗野!我认为这是不可能的,因为reraise对应于从堆栈顶部捕获异常的特殊IL指令,但是异步表达式被编译成连续链的方式,我认为语义不成立 出于同样的原因,以下内容也不会编译:
try
(null:string).ToString()
with e ->
(fun () -> reraise())()
在这些情况下,如果我需要使用正文在实际的之外处理异常,并且希望模拟重新调用
(即,保留异常的堆栈跟踪),我将使用解决方案,因此您的所有代码看起来如下所示:
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)
}
let inline reraisePreserveStackTrace(e:异常)=
让remoteStackTraceString=typeof.GetField(“_remoteStackTraceString”,BindingFlags.Instance | | | BindingFlags.NonPublic”);
SetValue(e,e.StackTrace+Environment.NewLine);
提高e
让executeAsync上下文=异步{
traceContext.Properties.Add(“CorrelationId”,context.CorrelationId)
尝试
do!runAsync上下文
一无所获
具有
|e当出现临界异常时(e)->
对数临界异常
重新启用保留跟踪
|e->
Loge例外
返回一些(e)
}
更新:.NET 4.5已推出,它可以更清晰地实现上述reraisePreserveStackTrace
我在不同的环境中遇到了类似的问题,但归根结底就是这个问题
异常不能抛出到不同的线程上-调用reraise()
需要一个异常处理程序在某种意义上运行在代码中原始异步块的“上方”
let runAsync context = async {return ()}
let isCriticalException e = true
let logCriticalException e = ()
let logException e = ()
let executeAsync context =
async {
do! runAsync context
return None
}
let run =
match executeAsync 5 |> Async.Catch |> Async.RunSynchronously with
|Choice1Of2(t) ->
printfn "%A" t
None
|Choice2Of2(exn) ->
match exn with
| e when isCriticalException(e) ->
logCriticalException e
raise (new System.Exception("See inner exception",e)) //stack trace will be lost at this point if the exn is not wrapped
| e ->
logException e
Some(e)
注意,我们仍然不能使用reraise,因为我们现在调用的是另一个线程,所以我们将异常封装在另一个线程中它比不能从另一个线程调用reraise更具体,它不能从另一个stackframe调用。这个答案可能已经过时了。在.net 4.5中,您可以使用ExceptionDispatchInfo
类,该类可以执行此操作,还可以捕获Watson bucket信息,例如原点装配和IL偏移@DaxFohl可以使用ExceptionDispatchInfo
提供最新答案吗?我已将此作为F#建议提交,能否请各位投票?我把这个作为一个F#建议提交给你,你能告诉我你的家人吗?