Con un po 'di hacking piuttosto orribile, è possibile utilizzare il tipo MailboxProcessor
da C# utilizzando async
. Alcune difficoltà sono che il tipo utilizza alcune caratteristiche specifiche di F # (gli argomenti facoltativi sono opzioni, le funzioni sono FSharpFunc
, ecc.)
Tecnicamente, la più grande differenza è che F # async viene disattivato mentre C# async crea un'attività già in esecuzione . Ciò significa che per costruire F # async da C#, è necessario scrivere un metodo che richiede unt -> Task<T>
e crea Async<T>
. Ho scritto un blog post that discusses the difference.
Anwyay, se si vuole sperimentare, qui è un codice è possibile utilizzare:
static FSharpAsync<T> CreateAsync<T>(Func<Task<T>> f)
{
return FSharpAsync.FromContinuations<T>(
FuncConvert.ToFSharpFunc<
Tuple< FSharpFunc<T, Unit>,
FSharpFunc<Exception, Unit>,
FSharpFunc<OperationCanceledException, Unit> >>(conts => {
f().ContinueWith(task => {
try { conts.Item1.Invoke(task.Result); }
catch (Exception e) { conts.Item2.Invoke(e); }
});
}));
}
static void MailboxProcessor() {
var body = FuncConvert.ToFSharpFunc<
FSharpMailboxProcessor<int>,
FSharpAsync<Unit>>(mbox =>
CreateAsync<Unit>(async() => {
while (true) {
var msg = await FSharpAsync.StartAsTask
(mbox.Receive(FSharpOption<int>.None),
FSharpOption<TaskCreationOptions>.None,
FSharpOption<CancellationToken>.None);
Console.WriteLine(msg);
}
return null;
}));
var agent = FSharpMailboxProcessor<int>.Start(body,
FSharpOption<CancellationToken>.None);
agent.Post(1);
agent.Post(2);
agent.Post(3);
Console.ReadLine();
}
Come si può vedere, questo sembra davvero orribile :-).
In linea di principio, potrebbe essere possibile scrivere un C# involucro accogliente per il tipo di MailboxProcessor
(basta estrarre i bit brutte di questo codice), ma ci sono alcuni problemi.
In F # si utilizzano spesso async ricorsive per implementare la macchina a stati nel processore di cassette postali. Se scrivi la stessa cosa in C#, alla fine otterrai StackOverflow
, quindi dovresti scrivere loop con stato mutabile.
È perfettamente possibile scrivere l'agente in F # e chiamarlo da C#. Questo è solo questione di esporre l'interfaccia C# -friendly da F # (usando il metodo Async.StartAsTask
).
fonte
2010-11-02 13:43:58
Potrebbe risolvere il collegamento interrotto? – czifro
@czifro, ok fatto. – Benjol