Thomas
Thomas

Reputation: 12127

Calling, and awaiting, an F# async method, from C#

I have this in F#:

type RuleStore() =

    ...
    static member LoadAsync : Async<RulesStore> =
        async {
            let! r = Startup.States.GetAsStringAsync("rules") |> Async.AwaitTask

            return
                if String.IsNullOrEmpty r then
                    new RulesStore()
                else
                    JsonConvert.DeserializeObject<RulesStore>(r);
        }

and I am trying to call it from C#, but the syntax doesn't seem to work.

NewRules = await Rules.RulesStore.LoadAsync();

The error I get is:

Core.cs(29, 38): [CS1955] Non-invocable member 'Rules.RulesStore.LoadAsync' cannot be used like a method.

which I don't quite understand because I'm under the impression that LoadAsync is just a static method.

Upvotes: 1

Views: 184

Answers (1)

Tomas Petricek
Tomas Petricek

Reputation: 243126

There are two reasons why you can't call await Rules.RulesStore.LoadAsync().

First, your code is actually defining a get-only property. In F#, the syntax for defining a get-only property is quite similar to the syntax for defining methods:

static member LoadAsync : Async<RulesStore> =   // Defines a get-only property
static member LoadAsync() : Async<RulesStore> = // Defines a method

You could go with a get-only property and call await Rules.RulesStore.LoadAsync, but that would probably seem odd to C# callers, so method seems a better option.

Second, your code is returning Async<'T> but C# works with Task<'T> type instead. You could convert Async to Task in C#, but it is easier to do this on the F# side. To do this, you need to change the type and add Async.StartAsTask to the end (as a personal stylistic preference, I'd also have return inside if, but that's just because I think it looks nicer):

type RuleStore() =

    ...
    static member LoadAsync : Task<RulesStore> =
        async {
            let! r = Startup.States.GetAsStringAsync("rules") |> Async.AwaitTask
            if String.IsNullOrEmpty r then
                return new RulesStore()
            else
                return JsonConvert.DeserializeObject<RulesStore>(r);
        } |> Async.StartAsTask

Upvotes: 5

Related Questions