Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/macos/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Asynchronous 如何在F#中的异步工作流中使用reraise?_Asynchronous_Exception Handling_F#_F# Async - Fatal编程技术网

Asynchronous 如何在F#中的异步工作流中使用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

我需要在记录异常后,重新释放在执行异步块时发生的异常

当我执行以下操作时,编译器认为我没有从处理程序中调用reraise函数。我做错了什么

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#建议提交给你,你能告诉我你的家人吗?