Ответ 1
Я думаю, причина, по которой MailboxProcessor
в F # не содержит какого-либо механизма обработки исключений, заключается в том, что неясно, как лучше всего это сделать. Например, вы можете захотеть иметь глобальное событие, которое запускается, когда происходит необработанное исключение, но вы можете захотеть повторить исключение при следующем вызове Post
или PostAndReply
.
Оба варианта могут быть реализованы на основе стандартного MailboxProcessor
, поэтому можно добавить нужное поведение. Например, в следующем фрагменте показан HandlingMailbox
, который добавляет глобальный обработчик исключений. Он имеет тот же интерфейс, что и обычный MailboxProcessor
(я пропустил некоторые методы), но он добавляет событие OnError
, которое запускается при возникновении исключения:
type HandlingMailbox<'T> private(f:HandlingMailbox<'T> -> Async<unit>) as self =
let event = Event<_>()
let inbox = new MailboxProcessor<_>(fun inbox -> async {
try
return! f self
with e ->
event.Trigger(e) })
member x.OnError = event.Publish
member x.Start() = inbox.Start()
member x.Receive() = inbox.Receive()
member x.Post(v:'T) = inbox.Post(v)
static member Start(f) =
let mbox = new HandlingMailbox<_>(f)
mbox.Start()
mbox
Чтобы использовать его, вы должны написать тот же код, что и ранее, но вы можете обрабатывать исключения асинхронно:
let counter = HandlingMailbox<_>.Start(fun inbox -> async {
while true do
printfn "waiting for data..."
let! data = inbox.Receive()
failwith "fail" })
counter.OnError.Add(printfn "Exception: %A")
counter.Post(42)