在F#中使用TaskCompletionSource以在.NET库中使用
考虑到以下几点:在F#中使用TaskCompletionSource以在.NET库中使用,f#,F#,考虑到以下几点: type MyClass () = member x.ReadStreamAsync(stream:Stream) = async { let tcs = new TaskCompletionSource<int>() let buffer = Array.create 2048 0uy let! bytesReadCount = stream.ReadAsync(bu
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
}
键入MyClass()=
成员x.ReadStreamAsync(流:流)=
异步的{
让tcs=new TaskCompletionSource()
让buffer=Array.create 2048 0uy
let!bytesReadCount=stream.ReadAsync(buffer,0,buffer.Length)|>Async.waitTask
如果ByteReadCount>0,则
对于0中的i..ByteReadCount do
如果缓冲区[i]=10uy,则
tcs.SetResult(一)
//如果未找到10uy,则省略更多代码来处理此情况。。
返回tcs.Task
}
代码从流中读取,直到in遇到某个字符(由字节值表示),此时方法返回的任务完成
DoSomethingAsync
的函数签名是unit->Async
,但我希望它是unit->Task
,这样就可以在.NET中更普遍地使用它
这可以在F#中使用异步表达式来完成吗?或者我可以更依赖.NET的
任务结构吗?鉴于您的示例中没有实际使用异步工作流,最简单的解决方案是完全放弃它:
member x.DoSomethingAsync() =
let tcs = new TaskCompletionSource<int>()
Task.Delay(100).Wait()
tcs.SetResult(10)
tcs.Task
此实现还具有类型unit->Task
根据更新的问题,这里有一种方法:
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
。我不知道在的情况下要做什么,所以我只是把-1
,但我相信你可以用更正确的东西来代替它。考虑到你的示例中没有实际使用异步工作流,最简单的解决方案是完全放弃它:
member x.DoSomethingAsync() =
let tcs = new TaskCompletionSource<int>()
Task.Delay(100).Wait()
tcs.SetResult(10)
tcs.Task
此实现还具有类型unit->Task
根据更新的问题,这里有一种方法:
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
。我不知道在else
的情况下该怎么办,所以我只放了-1
,但我相信您可以用更正确的东西来替换它。给定的代码没有编译…添加了类以使其编译。它仍然没有编译。。。罪魁祸首是Async.AwaitTask
,它没有将Task
作为参数。Hmm。真奇怪。它在这里编译。另请参见给定的代码未编译…添加类使其编译。它仍然未编译。。。罪魁祸首是Async.AwaitTask
,它没有将Task
作为参数。Hmm。真奇怪。它在这里编译。另请参见假设我们返回的不是Task.Delay
,而是SetResult
所需的内容(示例中使用Delay是为了简洁)。难道我们不需要使用let等待结果吗代码>因此需要计算表达式?可能示例构造得不好。我试图更新它,希望它能更清楚地表达我的意图。@ploeh如果缓冲区
还没有包含分隔符,那么函数应该再次调用自己来读取更多的流,而不是用-1来完成任务。当分隔符最终到达流中时,任务最终可以完成。这就是我试图用TaskCompletionSource建模的行为。我能理解startask
使这更容易,因为我认为else
块可以再次调用DoSomethingAsync
。@lejon听起来很合理,尽管您可能需要一个递归函数来实现这一点。@p谢谢您的输入和回答。假设我们返回的不是Task.Delay
,而是SetResult
所需的内容(示例中使用Delay是为了简洁)。难道我们不需要使用let等待结果吗代码>因此需要计算表达式?可能示例构造得不好。我试图更新它,希望它能更清楚地表达我的意图。@ploeh如果缓冲区
还没有包含分隔符,那么函数应该再次调用自己来读取更多的流,而不是用-1来完成任务。当分隔符最终到达流中时,任务最终可以完成。这就是我试图用TaskCompletionSource建模的行为。我很欣赏startask
使这更容易,因为我认为else
块可以再次调用DoSomethingAsync
。@lejon听起来很合理,不过您可能需要一个递归函数来实现它。@ploeh感谢您的输入和回答。