Podczas korzystania z zadania <T> podczas wykonywania zadania jest zgłaszany wyjątek podczas Task.Wait(); podczas korzystania z MailBoxProcessor F #, wyjątek zostaje połknięty i musi być jawnie rozpatrzony zgodnie z this question.Ujednolicanie zadania i obsługa wyjątków Faila MailboxProcessor
Ta różnica utrudnia wystawienie agentów F # na kod C# za pomocą zadania. Na przykład, ten agent:
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)))
może być wywołana z C#, ale sytuacja ta nie jest zwracana do C#:
[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);
}
}
Zamiast się wyjątek, kod C# po prostu wisi w task.Wait(). Czy istnieje sposób, aby agent F # zachowywał się jak zadanie? Jeśli nie, wydaje się, że korzystanie z agentów F # jest ograniczone do innego kodu .NET.
Dzięki, właśnie tego szukałem! Nie mam głowy wokół 'return (raise e)' będąc legalną konstrukcją, mimo że mój kod używał podobnego 'powrotu! failwith "Boom!" '. – Akash
'raise' jest zdefiniowane jako zwracające' 'T', ale oczywiście nigdy tak naprawdę nie wraca. Dzięki temu można go używać w dowolnym miejscu, niezależnie od typu otaczającego wyrażenia. – Daniel
@Akash: Możesz również napisać: 'return match res z odpowiedzią i -> i | Błąd e -> podnieś e'. – Daniel