Reputation: 100238
Say I have interface:
interface IProductRepository
{
Task SaveProduct(Product p);
}
previously implemented by C# class:
class CSharpProductRepository : IProductRepository
{
public Task SaveProduct(Product p)
{
_db.Products.Add(p);
return _db.SaveChangesAsync();
}
}
Now I want to implement the same in F#:
type FSharpProductRepository =
interface IProductRepository with
member this.SaveProduct(p : Product) : Task = this.SaveProduct(p) // error 1
member this.SaveProduct(p : Product) = async {
db.Products.Add(p)
return db.SaveChangesAsync() |> Async.AwaitTask // error 2
}
But getting an error (1):
This expression was expected to have type Task but here has type Async<'a>
and (2):
Type constraint mismatch. The type Task is not compatible with type Task<'a>
Upvotes: 3
Views: 816
Reputation: 16782
Given that Task<'a>
is a subtype of Task
you can do smth like this:
open System.Threading.Tasks
// stubs since I don't know what the actual code looks like
type Product = class end
type IProductRepository =
abstract SaveProduct: product: Product -> Task
type Db =
abstract Products: System.Collections.Generic.ICollection<Product>
abstract SaveProductAsync: product: Product -> Task<int>
type Repository(db: Db) =
interface IProductRepository with
member this.SaveProduct(p: Product) =
db.Products.Add(p)
upcast db.SaveProductAsync(p)
Upvotes: 6
Reputation: 52270
you need to start the async
workflow with Async.StartAsTask
but sadly that does not work here as this will need a generic task Task<'a>
:( - so I think you have to use the AwaitWaitHandle
method with the tasks AsyncWaitHanlde
type FSharpProductRepository =
interface IProductRepository with
member this.SaveProduct(p : Product) : Task =
this.SaveProduct(p)
member this.SaveProduct(p : Product) =
async {
db.Product.Add(p)
let task = db.SaveChangesAsync()
let! _ = Async.AwaitWaitHandle (task :> IAsyncResult).AsyncWaitHandle
return ()
} |> Async.StartAsTask :> _
It makes more sense to return the task directly, as in the code above (that just mirrors
the C# implementation) it just starts a thread, that starts another (db.SaveChanges()
) waits for the changes to be saved and returns ... seems overkill to me.
This only would IMO only make sense if you would continue to work with the async
-Workflow (remove the Async.StartAsTask
- or if you would use the overload of AwaitWaitHandle
that
will timeout after some milliseconds).
member this.SaveProduct(p : Product) =
db.Product.Add(p)
db.SaveChangesAsync()
Upvotes: 4