5 people like it.
Like the snippet!
Reraise everywhere!
Implements a technique found in http://stackoverflow.com/a/2085377. Useful for rethrowing exceptions in the context of computation expressions, not otherwise possible, as well as a few other applications.
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
|
open System.Reflection
let internal clone (e : #exn) =
let bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter()
use m = new System.IO.MemoryStream()
bf.Serialize(m, e)
m.Position <- 0L
bf.Deserialize m :?> exn
let internal remoteStackTraceField =
let getField name = typeof<System.Exception>.GetField(name, BindingFlags.Instance ||| BindingFlags.NonPublic)
match getField "remote_stack_trace" with
| null ->
match getField "_remoteStackTraceString" with
| null -> failwith "a piece of unreliable code has just failed."
| f -> f
| f -> f
let inline reraise' (e : #exn) =
// clone the exception to avoid mutation side-effects
let e' = clone e
remoteStackTraceField.SetValue(e', e'.StackTrace + System.Environment.NewLine)
raise e'
// examples
type Test =
static member Factorial (n : int) =
if n = 0 then failwith "boom!"
else
n * Test.Factorial(n-1)
try Test.Factorial 42
with e -> reraise' e
// reraise in workflows
async {
try return Test.Factorial 42
with e -> return reraise' e
} |> Async.RunSynchronously
// unpacking TargetInvocationExceptions without losing the inner stacktrace
type MethodInfo with
member m.GuardedInvoke(instance : obj, parameters : obj []) =
try m.Invoke(instance, parameters)
with :? TargetInvocationException as e when e.InnerException <> null ->
reraise' e.InnerException
typeof<Test>.GetMethod("Factorial").GuardedInvoke(null, [| 42 :> obj |])
|
namespace System
namespace System.Reflection
val internal clone : e:#exn -> exn
Full name: Script.clone
val e : #exn
type exn = System.Exception
Full name: Microsoft.FSharp.Core.exn
val bf : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
namespace System.Runtime
namespace System.Runtime.Serialization
namespace System.Runtime.Serialization.Formatters
namespace System.Runtime.Serialization.Formatters.Binary
Multiple items
type BinaryFormatter =
new : unit -> BinaryFormatter + 1 overload
member AssemblyFormat : FormatterAssemblyStyle with get, set
member Binder : SerializationBinder with get, set
member Context : StreamingContext with get, set
member Deserialize : serializationStream:Stream -> obj + 1 overload
member DeserializeMethodResponse : serializationStream:Stream * handler:HeaderHandler * methodCallMessage:IMethodCallMessage -> obj
member FilterLevel : TypeFilterLevel with get, set
member Serialize : serializationStream:Stream * graph:obj -> unit + 1 overload
member SurrogateSelector : ISurrogateSelector with get, set
member TypeFormat : FormatterTypeStyle with get, set
...
Full name: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
--------------------
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter() : unit
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(selector: System.Runtime.Serialization.ISurrogateSelector, context: System.Runtime.Serialization.StreamingContext) : unit
val m : System.IO.MemoryStream
namespace System.IO
Multiple items
type MemoryStream =
inherit Stream
new : unit -> MemoryStream + 6 overloads
member CanRead : bool
member CanSeek : bool
member CanWrite : bool
member Capacity : int with get, set
member Flush : unit -> unit
member GetBuffer : unit -> byte[]
member Length : int64
member Position : int64 with get, set
member Read : buffer:byte[] * offset:int * count:int -> int
...
Full name: System.IO.MemoryStream
--------------------
System.IO.MemoryStream() : unit
System.IO.MemoryStream(capacity: int) : unit
System.IO.MemoryStream(buffer: byte []) : unit
System.IO.MemoryStream(buffer: byte [], writable: bool) : unit
System.IO.MemoryStream(buffer: byte [], index: int, count: int) : unit
System.IO.MemoryStream(buffer: byte [], index: int, count: int, writable: bool) : unit
System.IO.MemoryStream(buffer: byte [], index: int, count: int, writable: bool, publiclyVisible: bool) : unit
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(serializationStream: System.IO.Stream, graph: obj) : unit
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(serializationStream: System.IO.Stream, graph: obj, headers: System.Runtime.Remoting.Messaging.Header []) : unit
property System.IO.MemoryStream.Position: int64
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(serializationStream: System.IO.Stream) : obj
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(serializationStream: System.IO.Stream, handler: System.Runtime.Remoting.Messaging.HeaderHandler) : obj
val internal remoteStackTraceField : FieldInfo
Full name: Script.remoteStackTraceField
val getField : (string -> FieldInfo)
val name : string
val typeof<'T> : System.Type
Full name: Microsoft.FSharp.Core.Operators.typeof
Multiple items
type Exception =
new : unit -> Exception + 2 overloads
member Data : IDictionary
member GetBaseException : unit -> Exception
member GetObjectData : info:SerializationInfo * context:StreamingContext -> unit
member GetType : unit -> Type
member HelpLink : string with get, set
member InnerException : Exception
member Message : string
member Source : string with get, set
member StackTrace : string
...
Full name: System.Exception
--------------------
System.Exception() : unit
System.Exception(message: string) : unit
System.Exception(message: string, innerException: exn) : unit
type BindingFlags =
| Default = 0
| IgnoreCase = 1
| DeclaredOnly = 2
| Instance = 4
| Static = 8
| Public = 16
| NonPublic = 32
| FlattenHierarchy = 64
| InvokeMethod = 256
| CreateInstance = 512
...
Full name: System.Reflection.BindingFlags
field BindingFlags.Instance = 4
field BindingFlags.NonPublic = 32
val failwith : message:string -> 'T
Full name: Microsoft.FSharp.Core.Operators.failwith
val f : FieldInfo
val reraise' : e:#exn -> 'b
Full name: Script.reraise'
val e' : exn
FieldInfo.SetValue(obj: obj, value: obj) : unit
FieldInfo.SetValue(obj: obj, value: obj, invokeAttr: BindingFlags, binder: Binder, culture: System.Globalization.CultureInfo) : unit
property System.Exception.StackTrace: string
type Environment =
static member CommandLine : string
static member CurrentDirectory : string with get, set
static member Exit : exitCode:int -> unit
static member ExitCode : int with get, set
static member ExpandEnvironmentVariables : name:string -> string
static member FailFast : message:string -> unit + 1 overload
static member GetCommandLineArgs : unit -> string[]
static member GetEnvironmentVariable : variable:string -> string + 1 overload
static member GetEnvironmentVariables : unit -> IDictionary + 1 overload
static member GetFolderPath : folder:SpecialFolder -> string + 1 overload
...
nested type SpecialFolder
nested type SpecialFolderOption
Full name: System.Environment
property System.Environment.NewLine: string
val raise : exn:System.Exception -> 'T
Full name: Microsoft.FSharp.Core.Operators.raise
type Test =
static member Factorial : n:int -> int
Full name: Script.Test
static member Test.Factorial : n:int -> int
Full name: Script.Test.Factorial
val n : int
Multiple items
val int : value:'T -> int (requires member op_Explicit)
Full name: Microsoft.FSharp.Core.Operators.int
--------------------
type int = int32
Full name: Microsoft.FSharp.Core.int
--------------------
type int<'Measure> = int
Full name: Microsoft.FSharp.Core.int<_>
static member Test.Factorial : n:int -> int
val e : exn
val async : AsyncBuilder
Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.async
Multiple items
type Async
static member AsBeginEnd : computation:('Arg -> Async<'T>) -> ('Arg * AsyncCallback * obj -> IAsyncResult) * (IAsyncResult -> 'T) * (IAsyncResult -> unit)
static member AwaitEvent : event:IEvent<'Del,'T> * ?cancelAction:(unit -> unit) -> Async<'T> (requires delegate and 'Del :> Delegate)
static member AwaitIAsyncResult : iar:IAsyncResult * ?millisecondsTimeout:int -> Async<bool>
static member AwaitTask : task:Task<'T> -> Async<'T>
static member AwaitWaitHandle : waitHandle:WaitHandle * ?millisecondsTimeout:int -> Async<bool>
static member CancelDefaultToken : unit -> unit
static member Catch : computation:Async<'T> -> Async<Choice<'T,exn>>
static member FromBeginEnd : beginAction:(AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg:'Arg1 * beginAction:('Arg1 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg1:'Arg1 * arg2:'Arg2 * beginAction:('Arg1 * 'Arg2 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg1:'Arg1 * arg2:'Arg2 * arg3:'Arg3 * beginAction:('Arg1 * 'Arg2 * 'Arg3 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromContinuations : callback:(('T -> unit) * (exn -> unit) * (OperationCanceledException -> unit) -> unit) -> Async<'T>
static member Ignore : computation:Async<'T> -> Async<unit>
static member OnCancel : interruption:(unit -> unit) -> Async<IDisposable>
static member Parallel : computations:seq<Async<'T>> -> Async<'T []>
static member RunSynchronously : computation:Async<'T> * ?timeout:int * ?cancellationToken:CancellationToken -> 'T
static member Sleep : millisecondsDueTime:int -> Async<unit>
static member Start : computation:Async<unit> * ?cancellationToken:CancellationToken -> unit
static member StartAsTask : computation:Async<'T> * ?taskCreationOptions:TaskCreationOptions * ?cancellationToken:CancellationToken -> Task<'T>
static member StartChild : computation:Async<'T> * ?millisecondsTimeout:int -> Async<Async<'T>>
static member StartChildAsTask : computation:Async<'T> * ?taskCreationOptions:TaskCreationOptions -> Async<Task<'T>>
static member StartImmediate : computation:Async<unit> * ?cancellationToken:CancellationToken -> unit
static member StartWithContinuations : computation:Async<'T> * continuation:('T -> unit) * exceptionContinuation:(exn -> unit) * cancellationContinuation:(OperationCanceledException -> unit) * ?cancellationToken:CancellationToken -> unit
static member SwitchToContext : syncContext:SynchronizationContext -> Async<unit>
static member SwitchToNewThread : unit -> Async<unit>
static member SwitchToThreadPool : unit -> Async<unit>
static member TryCancelled : computation:Async<'T> * compensation:(OperationCanceledException -> unit) -> Async<'T>
static member CancellationToken : Async<CancellationToken>
static member DefaultCancellationToken : CancellationToken
Full name: Microsoft.FSharp.Control.Async
--------------------
type Async<'T>
Full name: Microsoft.FSharp.Control.Async<_>
static member Async.RunSynchronously : computation:Async<'T> * ?timeout:int * ?cancellationToken:System.Threading.CancellationToken -> 'T
type MethodInfo =
inherit MethodBase
member Equals : obj:obj -> bool
member GetBaseDefinition : unit -> MethodInfo
member GetGenericArguments : unit -> Type[]
member GetGenericMethodDefinition : unit -> MethodInfo
member GetHashCode : unit -> int
member MakeGenericMethod : [<ParamArray>] typeArguments:Type[] -> MethodInfo
member MemberType : MemberTypes
member ReturnParameter : ParameterInfo
member ReturnType : Type
member ReturnTypeCustomAttributes : ICustomAttributeProvider
Full name: System.Reflection.MethodInfo
val m : MethodInfo
member MethodInfo.GuardedInvoke : instance:obj * parameters:obj [] -> obj
Full name: Script.GuardedInvoke
val instance : obj
type obj = System.Object
Full name: Microsoft.FSharp.Core.obj
val parameters : obj []
MethodBase.Invoke(obj: obj, parameters: obj []) : obj
MethodBase.Invoke(obj: obj, invokeAttr: BindingFlags, binder: Binder, parameters: obj [], culture: System.Globalization.CultureInfo) : obj
Multiple items
type TargetInvocationException =
inherit ApplicationException
new : inner:Exception -> TargetInvocationException + 1 overload
Full name: System.Reflection.TargetInvocationException
--------------------
TargetInvocationException(inner: exn) : unit
TargetInvocationException(message: string, inner: exn) : unit
val e : TargetInvocationException
property System.Exception.InnerException: exn
More information