С помощью довольно ужасного взлома вы можете использовать тип MailboxProcessor
из C #, используя async
.Некоторые трудности заключаются в том, что тип использует некоторые специфичные для F # функции (необязательные аргументы - это опции, функции имеют тип FSharpFunc
и т.это уже работает.Это означает, что для построения асинхронного F # из C # вам нужно написать метод, который принимает unt -> Task<T>
и создает Async<T>
.Я написал пост в блоге , в котором обсуждается разница .
Кстати, если вы хотите поэкспериментировать, вот код, который вы можете использовать:
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();
}
Как вы можетевидите, это выглядит действительно ужасно :-).
В принципе, можно написать C-дружественную оболочку для типа MailboxProcessor
(просто извлеките уродливые биты из этого кода), но есть некоторые проблемы.
В F # вы часто используете хвостовую рекурсивную асинхронность для реализации конечного автомата в процессоре почтовых ящиков.Если вы напишите то же самое в C #, вы в конечном итоге получите StackOverflow
, поэтому вам нужно будет писать циклы с изменяемым состоянием.
Совершенно возможно написать агентв F # и вызвать его из C #.Это всего лишь вопрос демонстрации C # -дружественного интерфейса из F # (используя метод Async.StartAsTask
).