运行以下代码时,出现Cannot access a disposed object错误(MyClient是由C#项目中的服务引用生成的WCF客户端)。

type Action =
    | Add
    | Update

let addStuff (myClient:MyClient) arg = async {
    let! response = myClient.AddAsync arg |> Async.AwaitTask
    return response.ID
}

let updateStuff (myClient:MyClient) arg = async {
    let! response = myClient.UpdateAsync arg |> Async.AwaitTask
    return response.ID
}

let doStuff arg =
    use myClient = new MyClient()
    match arg.Action with
    | Add -> arg |> addStuff myClient
    | Update -> arg |> updateStuff myClient

let args = [Add, Add, Update, Add]

let results =
    args
    |> List.map doStuff
    |> Async.Parallel


看来客户正在被我预料之中。如果我将doStuff更改为:

let doStuff arg = async {
    use myClient = new MyClient()
    return!
        match arg.Action with
        | Add -> arg |> addStuff myClient
        | Update -> arg |> updateStuff myClient
}


这两个函数的返回类型均为Async<int>。为什么在第一个示例中较早处置客户?我认为两个示例在逻辑上都是相同的。我的理解是,仅当需要使用async绑定时,才需要!工作流程,在这种情况下,我认为这是不必要的,因为特定功能中实际正在等待。

最佳答案

问题出在doStuff上:

let doStuff arg =
    use myClient = new MyClient()
    match arg.Action with
    | Add -> arg |> addStuff myClient
    | Update -> arg |> updateStuff myClient


您正在将myClient传递给捕获MyClient实例的异步函数。但是,当doStuff返回时,它将在Dispose实例上调用MyClient并处理客户端。当您的异步方法开始运行时,它使用的是已处置实例。

使doStuff起作用是因为处理成为异步工作流的一部分。

另一个选择是不use MyClient实例,而instean让addStuffupdateStuff创建自己的MyClient实例。

10-06 08:36