在F#中使用TaskCompletionSource用于.NET库

时间:2015-06-15 10:29:40

标签: f#

考虑以下

type MyClass () = 
    member x.ReadStreamAsync(stream:Stream) =
        async {
            let tcs = new TaskCompletionSource<int>()
            let buffer = Array.create 2048 0uy
            let! bytesReadCount = stream.ReadAsync(buffer, 0, buffer.Length) |> Async.AwaitTask
            if bytesReadCount > 0 then
                for i in 0..bytesReadCount do
                    if buffer.[i] = 10uy then
                        tcs.SetResult(i)

            // Omitted more code to handle the case if 10uy is not found..

            return tcs.Task
        }

代码从流中读取,直到遇到某个字符(由字节值表示),此时方法返回的任务完成。

DoSomethingAsync的函数签名是unit -> Async<Task<int>>,但我希望它是unit -> Task<int>,以便在.NET中更常用。

可以使用异步表达式在F#中完成,还是可以更多地依赖.NET的Task结构?

1 个答案:

答案 0 :(得分:6)

鉴于您实际上没有使用异步工作流来处理示例中的任何内容,最简单的解决方案是完全放弃它:

member x.DoSomethingAsync() =
    let tcs = new TaskCompletionSource<int>()
    Task.Delay(100).Wait()
    tcs.SetResult(10)
    tcs.Task

DoSomethingAsync的此实施具有unit -> Task<int>类型。

我不清楚你到底想要做什么,但为什么你不做以下事情?

member x.DoSomethingAsync() =
    async {
        do! Async.Sleep 100
        return 10 } |> Async.StartAsTask

此实现还具有类型unit -> Task<int>

根据更新的问题,这是一种方法:

member x.DoSomethingAsync(stream:Stream) =
    async {
        let buffer = Array.create 2048 0uy
        let! bytesReadCount =
            stream.ReadAsync(buffer, 0, buffer.Length) |> Async.AwaitTask
        if bytesReadCount > 0
        then
            let res =
                [0..bytesReadCount]
                |> List.tryFind (fun i -> buffer.[i] = 10uy)
            return defaultArg res -1
        else return -1
    }
    |> Async.StartAsTask

DoSomethingAsync函数的类型为Stream -> System.Task<int>。我在else案例中不知道该怎么做,所以我只是放-1,但我确定你可以用更正确的东西替换它。