假设我有一些C#代码需要回调:
void DoSomething(Action<string> callback);
Run Code Online (Sandbox Code Playgroud)
现在,我想在F#中使用它,但将其包装在一个async.我该怎么做?
// Not real code
let doSomething = async {
let mutable result = null
new Action(fun x -> result <- x) |> Tasks.DoSomething
// Wait for result to be assigned
return result
}
Run Code Online (Sandbox Code Playgroud)
例如,假设DoSomething看起来像这样:
module Tasks
let DoSomething callback =
callback "Hello"
()
Run Code Online (Sandbox Code Playgroud)
那么以下输出应该是"Hello":
let wrappedDoSomething = async {
// Call DoSomething somehow
}
[<EntryPoint>]
let main argv =
async {
let! resultOfDoSomething = wrappedDoSomething
Console.WriteLine resultOfDoSomething
return ()
} |> Async.RunSynchronously
0
Run Code Online (Sandbox Code Playgroud)
Async.FromContinuations函数可以说是Async的"最低级别".所有其他异步组合器都可以用它来表示.
它是最低级别,它直接编码异步计算的本质 - 在三种可能情况下做什么的知识:(1)成功完成前一个计算步骤,(2)崩溃先前的计算步骤,以及(3)从外部取消.这些可能的情况表示为传递给函数的三个函数类型参数Async.FromContinuations.例如:
let returnFive =
Async.FromContinuations( fun (succ, err, cancl) ->
succ 5
)
async {
let! res = returnFive
printfn "%A" res // Prints "5"
}
|> Async.RunSynchronously
Run Code Online (Sandbox Code Playgroud)
在这里,我的函数fun (succ, err, cancl) -> succ 5已经确定它已成功完成,并调用succcontinuation将其计算结果传递给下一步.
在您的情况下,该函数DoSomething仅表示三种情况中的一种 - 即"成功完成时该怎么做".一旦你进入回调,这意味着无论DoSomething做什么,都已成功完成.那时你需要调用succ延续:
let doSometingAsync =
Async.FromContinuations( fun (succ, err, cancl) ->
Tasks.DoSomething( fun res -> succ res )
)
Run Code Online (Sandbox Code Playgroud)
当然,您可以fun res -> succ res通过succ直接传递给DoSomething回调来避免嵌套的lambda表达式.不幸的是,你必须明确指定Action用于包装它的类型,这否定了优势:
let doSometingAsync =
Async.FromContinuations( fun (succ, err, cancl) ->
Tasks.DoSomething( System.Action<string> succ )
)
Run Code Online (Sandbox Code Playgroud)
顺便说一句,请注意,这立即在DoSomethingAPI中发现了一个漏洞:它忽略了错误情况.如果DoSomething没有做任何意图,会发生什么?您无法了解它,整个异步工作流程将会挂起.或者,更糟糕的是:进程将立即退出(取决于崩溃的发生方式).
如果您有任何控制权DoSomething,我建议您解决此问题.
| 归档时间: |
|
| 查看次数: |
138 次 |
| 最近记录: |