Bei Verwendung von Task <T> wird eine Ausnahme während der Ausführung der Task während Task.Wait() ausgelöst; Bei Verwendung des MailBoxProcessors von F # wird die Ausnahme verschluckt und muss explizit gemäß this question behandelt werden.Unifying Task <T> und F # MailboxProcessor Ausnahmebehandlung
Dieser Unterschied erschwert die Offenlegung von F # -Agenten gegenüber C# -Code über eine Task. Zum Beispiel dieses Mittel:
type internal IncrementMessage =
Increment of int * AsyncReplyChannel<int>
type IncrementAgent() =
let counter = Agent.Start(fun agent ->
let rec loop() = async { let! Increment(msg, replyChannel) = agent.Receive()
match msg with
| int.MaxValue -> return! failwith "Boom!"
| _ as i -> replyChannel.Reply (i + 1)
return! loop() }
loop())
member x.PostAndAsyncReply i =
Async.StartAsTask (counter.PostAndAsyncReply (fun channel -> Increment(i, channel)))
aus C# aufgerufen werden, sondern die Ausnahme ist nicht auf C# zurückgegeben:
[Test]
public void ExceptionHandling()
{
//
// TPL exception behaviour
//
var task = Task.Factory.StartNew<int>(() => { throw new Exception("Boom!"); });
try
{
task.Wait();
}
catch(AggregateException e)
{
// Exception available here
Console.WriteLine("Task failed with {0}", e.InnerException.Message);
}
//
// F# MailboxProcessor exception behaviour
//
var incAgent = new IncrementAgent();
task = incAgent.PostAndAsyncReply(int.MaxValue);
try
{
task.Wait(); // deadlock here
}
catch (AggregateException e)
{
Console.WriteLine("Agent failed with {0}", e.InnerException.Message);
}
}
statt die Ausnahme zu bekommen, die C# -Code hängt gerade bei task.Wait(). Gibt es eine Möglichkeit, den F # -Agenten dazu zu bringen, sich wie eine Aufgabe zu verhalten? Wenn dies nicht der Fall ist, scheint es nur eingeschränkt möglich zu sein, F # -Agenten anderen .NET-Code zur Verfügung zu stellen.
Danke, das ist genau das, was ich gesucht habe! Ich habe meinen Kopf nicht um 'return (raise e)' als ein rechtliches Konstrukt, obwohl mein Code eine ähnliche 'Rückkehr' verwendet! failwith "Boom!" '. – Akash
'Raise' ist definiert als Rückgabe von '' T ', aber natürlich kehrt es nie wirklich zurück. Dadurch kann es unabhängig vom umschließenden Ausdruckstyp überall verwendet werden. – Daniel
@Akash: Sie könnten auch schreiben: 'result match res mit Response i -> i | Fehler e -> raise e'. – Daniel