Xamarin F到C异步调用:正确的现代方式

Xamarin F到C异步调用:正确的现代方式,xamarin,f#,c#-to-f#,f#-async,Xamarin,F#,C# To F#,F# Async,我试图从Xamarin中的F代码同步调用C#Async函数。原始C#代码如下所示(这是Plugin.BLE目标设备服务发现): 如果我使用的是推荐的F#primitive module Async = let inline AwaitPlainTask (task: Task) = task.ContinueWith(fun t -> ()) |> Async.AwaitTask 以下代码: async { let! ser

我试图从Xamarin中的F代码同步调用C#Async函数。原始C#代码如下所示(这是Plugin.BLE目标设备服务发现):

如果我使用的是推荐的F#primitive

module Async =
    let inline AwaitPlainTask (task: Task) = 
       task.ContinueWith(fun t -> ())
       |> Async.AwaitTask 
以下代码:

async {
         let! service = Async.AwaitPlainTask <|d.GetServiceAsync(serviceGuid)
         let! characteristic = Async.AwaitPlainTask <|service.GetCharacteristicAsync(characteristicGuid)
...
serviceTask.Result始终为空。同样的结果(null)也会发生在

let! service = d.GetServiceAsync(serviceGuid) |> Async.AwaitTask
也是。C代码正在工作,所以基本上问题在于如何从F调用它。我想我在这里误解了什么,正确的方法是什么


注:这不是问题的重复,因为这可能已经过时,不再有效(至少在Xamarin上是如此)。

您在这里使用的函数
等待任务
,看起来它是一个处理
任务的便利函数。但是,在F#
异步
计算表达式中有一种处理
任务
的标准方法。您应该使用
Async.AwaitTask
,以及
let,如下所示:

async {
    // Removing back-pipes as they are often more confusing that useful
    let! service = d.GetServiceAsync(serviceGuid) |> Async.AwaitTask
    let! characteristic = service.GetCharacteristicAsync(characteristicGuid) |> Async.AwaitTask
...
否则,你所做的就是将
Task
转换为
Task
并尝试等待它:

var result = await ((Task)d.GetServiceAsync(serviceGuid))
它不会在C#中编译,但是在F#中我们有
单元
类型,它实际上非常方便,因为您不需要大量的类型和泛型代码重载

还值得注意的是,您可能可以删除
awaitplantask
,因为它现在是自F#4.0以来内置的
Async.AwaitTask
的重载,例如:

let waitOneSecond () = async {
    // Use do! not let! when you aren't using the result
    do! Task.Delay(1000) |> Async.AwaitTask
}
let! service = d.GetServiceAsync(serviceGuid) |> Async.AwaitTask
let service = service |> Option.ofObj
match service with
| Some s -> let! characteristic = s.GetCharacteristicAsync(characteristicGuid) |> Async.AwaitTask
            ()
| None ->   ()
我已经看过了
Plugin.BLE
,它看起来像是等待
GetServiceAsync
可以返回
null
,正如您所说,这是库的设计

为了处理这个问题,我们可以将结果包装成一个
选项
类型,并将其作为一种安全的方式在之后访问它。例如:

let waitOneSecond () = async {
    // Use do! not let! when you aren't using the result
    do! Task.Delay(1000) |> Async.AwaitTask
}
let! service = d.GetServiceAsync(serviceGuid) |> Async.AwaitTask
let service = service |> Option.ofObj
match service with
| Some s -> let! characteristic = s.GetCharacteristicAsync(characteristicGuid) |> Async.AwaitTask
            ()
| None ->   ()

正如我在问题中提到的,
let!service=d.GetServiceAsync(serviceGuid)|>Async.AwaitTask
为服务返回null。(C#相同情况下的代码有效)@Darkkey如果这个答案有用,请记住标记:)@JuniorJiang MSFT这个答案没有帮助不幸的是,它表明了我已经尝试过的方式(包括在问题中)。正如我在上面的评论中提到的,它不起作用(服务变为null)。这不是库的问题,因为等效的C代码正在工作。啊,我理解。我会在几个小时内更新我的答案。