如何在F#中实现返回Task(非泛型)的方法的接口

时间:2014-10-07 16:32:24

标签: c# f# task-parallel-library async-await c#-to-f#

说我有界面:

interface IProductRepository
{
    Task SaveProduct(Product p);
}

以前由C#类实现:

class CSharpProductRepository : IProductRepository
{
    public Task SaveProduct(Product p)
    {
        _db.Products.Add(p);
        return _db.SaveChangesAsync();
    }
}

现在我想在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
    }

但是得到错误(1):

  

此表达式应该具有Task类型,但此处的类型为Async<' a>

和(2):

  

类型约束不匹配。类型任务与类型任务<' a>

不兼容

2 个答案:

答案 0 :(得分:5)

鉴于Task<'a>Task的子类型,你可以像这样做:

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)

答案 1 :(得分:4)

您需要使用async启动Async.StartAsTask工作流程,但遗憾的是,这不起作用,因为这需要通用任务Task<'a> :( - 所以我认为您必须使用任务AwaitWaitHandle

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 :> _

直接返回任务:

直接返回任务更有意义,就像上面的代码一样(只是镜像) C#实现)它只是启动一个线程,启动另一个线程(db.SaveChanges())等待保存更改并返回......对我来说似乎有点过分了。

只有当您继续使用async - 工作流程(删除Async.StartAsTask - 或者您将使用AwaitWaitHandle的重载时,IMO才会有意义 会在几毫秒后超时。)

    member this.SaveProduct(p : Product) = 
      db.Product.Add(p)
      db.SaveChangesAsync()