I'm trying to call C# Async function synchronously from F# code in Xamarin. The original C# code looks like (this is the Plugin.BLE target device service discovery):
{
var service = await _connectedDevice.GetServiceAsync(serviceGuid);
if (service != null)
{
var characteristic = await service.GetCharacteristicAsync(Guid.Parse(characteristicGuid);
if (characteristic != null)
{
If I'm using recommended F# primitive
module Async =
let inline AwaitPlainTask (task: Task) =
task.ContinueWith(fun t -> ())
|> Async.AwaitTask
The following code:
async {
let! service = Async.AwaitPlainTask <|d.GetServiceAsync(serviceGuid)
let! characteristic = Async.AwaitPlainTask <|service.GetCharacteristicAsync(characteristicGuid)
...
could not be compiled because 'The field, constructor or member 'GetCharacteristicAsync' is not defined.'. Seems F# could not correctly determine or convert type after AwaitPlainTask.
If I'm trying to do it in the regular way, e.g.:
async {
let serviceTask = d.GetServiceAsync(serviceGuid)
serviceTask.Wait()
let tsk = serviceTask.Result.ToString()
the serviceTask.Result is always null. The same result (null) happens for
let! service = d.GetServiceAsync(serviceGuid) |> Async.AwaitTask
too. C# code is working, so basically the problem is with how it's called from F#. I think I misunderstood something here, what is the correct way to deal with this type of constructions?
P.S.: It's not a duplicate of this question, because that probably is outdated and no longer works (at least on Xamarin).
The function you are using here
AwaitPlainTask, looks like it's a convenience function to deal withTask. However there is a standard way of dealing withTask<T>in F#asynccomputation expressions. You should be usingAsync.AwaitTask, along withlet!, like this:What you are doing otherwise is the equivalent in C# of casting
Task<T>toTaskand trying to await it:which wouldn't compile in C#, however in F# we have the
unittype, which actually is really handy as you don't a proliferation of types and overloads of generic code.It's also worth noting that you can probably delete
AwaitPlainTaskas it now is an overload of the build inAsync.AwaitTasksince F# 4.0, for example:I've had a look at
Plugin.BLEand it looks like awaitngGetServiceAsynccan returnnullas you say, it is the design of the library.To handle this, we could wrap the result in an
Optiontype and use that as a safe way to access it after. For example: