Обычно не рекомендуется выставлять типы F #, такие как FSharpAsync
, в общедоступном интерфейсе, который будет использоваться клиентами C # (см. Рекомендации по проектированию компонентов F # ). Вы можете использовать Async.StartAsTask
(на стороне F #), чтобы представить операцию как Task<T>
, которую легко использовать из C #.
Фактически, я бы также заменил кортеж на именованный тип (который отражает значение структуры данных). Кортежи могут использоваться в C #, но они не являются идиоматическими в C #:
// Assuming you have an operation like this
let asyncDoWork () : Async<seq<DateTime * string>> = (...)
// Define a named type that explains what the date-string pair means
type Item(created:DateTime, name:string) =
member x.Created = created
member x.Name = name
// Create a simple wrapper that wraps values into 'Item' type
let asyncDoWorkItems () =
async { let! res = asyncDoWork()
return seq { for (d, n) in res -> Item(d, n) } }
Теперь, чтобы представить операцию на C #, лучше всего использовать тип с перегруженным статическим методом. Метод запускает операцию как задачу, и одна перегрузка указывает токен отмены. Соглашение об именах C # для них заключается в добавлении Async
к end имени (которое не совпадает с F #, которое добавляет Async
впереди):
type Work =
static member DoWorkAsync() =
Async.StartAsTask(asyncDoWorkItems())
static member DoWorkAsync(cancellationToken) =
Async.StartAsTask(asyncDoWorkItems(), cancellationToken = cancellationToken)
Ваш код C # может затем использовать Work.DoWorkAsync()
и работать с задачей в обычном стиле C #. Он даже будет работать с ключевым словом await
, которое (вероятно) будет добавлено в C # 5.