首先,在您的用例中,不需要async { } 块。 Async.AwaitTask returns an Async<'T>,所以你的 async { } 块只是解开你得到的 Async 对象并立即重新包装它。
现在我们已经摆脱了不必要的async 块,让我们看看您获得的类型,以及您想要获得的类型。你有一个Async<'a>,并且你想要一个'a 类型的对象。查看available Async functions,具有Async<'a> -> 'a 之类的类型签名的是Async.RunSynchronously。它需要两个可选参数,一个int 和一个CancellationToken,但如果你把它们去掉,你就会得到你正在寻找的函数签名。果然,一旦您查看文档,就会发现 Async.RunSynchronously 是 C# 的 await 的 F# 等价物,这正是您想要的。 有点(但不完全是)类似于 C# 的 @ 987654341@。 C# 的 await 是可以在 async 函数中使用的语句,而 F# 的 Async.RunSynchronously 采用 async 对象阻塞当前线程,直到 async 对象完成运行。在这种情况下,这正是您要寻找的。p>
let readEventFromEventStore<'a when 'a : not struct> (eventStore:IEventStoreRepository) (streamName:string) (position:int) =
eventStore.ReadEventAsync(streamName, position)
|> Async.AwaitTask
|> Async.RunSynchronously
这应该可以满足您的需求。并注意找出所需函数的函数签名的技术,然后寻找具有该签名的函数。对未来会有很大帮助。
更新:感谢 Tarmil 指出我在 cmets 中的错误:Async.RunSynchronously 不等同于 C# 的 await。它非常相似,但是由于RunSynchronously 阻塞了当前线程,因此需要注意一些重要的细节。 (你不想在你的 GUI 线程中调用它。)
更新 2:当您想在不阻塞当前线程的情况下等待异步结果时,通常是这样的模式的一部分:
- 调用一些异步操作
- 等待结果
- 用这个结果做点什么
编写该模式的最佳方式如下:
let equivalentOfAwait () =
async {
let! result = someAsyncOperation()
doSomethingWith result
}
以上假设doSomethingWith 返回unit,因为您调用它是因为它的副作用。如果它返回一个值,你会这样做:
let equivalentOfAwait () =
async {
let! result = someAsyncOperation()
let value = someCalculationWith result
return value
}
或者,当然:
let equivalentOfAwait () =
async {
let! result = someAsyncOperation()
return (someCalculationWith result)
}
假设someCalculationWith 不是异步操作。相反,如果您需要将两个异步操作链接在一起,其中第二个使用第一个的结果 - 或者甚至以某种序列的三个或四个异步操作 - 那么它看起来像这样:
let equivalentOfAwait () =
async {
let! result1 = someAsyncOperation()
let! result2 = nextOperationWith result1
let! result3 = penultimateOperationWith result2
let! finalResult = finalOperationWith result3
return finalResult
}
除了let! 后跟return 完全等价于return!,所以最好写成:
let equivalentOfAwait () =
async {
let! result1 = someAsyncOperation()
let! result2 = nextOperationWith result1
let! result3 = penultimateOperationWith result2
return! (finalOperationWith result3)
}
所有这些函数都将产生一个Async<'T>,其中'T 将是async 块中最终函数的返回类型。要真正运行这些异步块,您可以像已经提到的那样执行Async.RunSynchronously,或者您可以使用各种Async.Start 函数之一(Start、StartImmediate、StartAsTask 、StartWithContinuations 等)。 Async.StartImmediate example 也谈到了Async.SwitchToContext function,这可能是您想要阅读的内容。但我对SynchronizationContexts 不够熟悉,无法告诉您更多信息。