【问题标题】:This expression was expected to have type Async<'a> but here has type DispatcherOperation此表达式应具有 Async<'a> 类型,但此处具有 DispatcherOperation 类型
【发布时间】:2017-01-03 15:57:43
【问题描述】:

我正在构建一个包含 F# 文件的项目,并且在构建期间第 39 行出现错误:

这个表达式应该有类型 Async 但这里有类型 DispatcherOperation

open System
open System.Collections.Generic
open System.Collections.ObjectModel
open System.Linq
open System.Net
open System.Reactive.Disposables
open System.Runtime.CompilerServices
open System.Threading
open System.Windows
open System.Windows.Threading

open Microsoft.Practices.Unity

type IActivityContext<'TResult> = interface
    abstract container: IUnityContainer
    abstract Success: result:'TResult -> unit
    abstract Error: error:Exception -> unit
    abstract Cancel: unit -> unit
    abstract RegisterCancellationCallback: callback:Action->IDisposable
end

[<Extension>]
type ActivityExtensions private() = class
    [<Extension>]
    static member StartViewActivity<'TResult>(container: IUnityContainer, callback: Action<IActivityContext<'TResult>>)= async{
        let! ct = Async.CancellationToken
        return! Async.FromContinuations(fun (success, error, cancel) ->
            let context = {
                new IActivityContext<'TResult> with
                    member this.container = container
                    member this.Success(result:'TResult) = success(result)
                    member this.Error(err:Exception) = error(err)
                    member this.Cancel() = cancel(new OperationCanceledException())
                    member this.RegisterCancellationCallback(callback: Action) = 
                        ct.Register(callback) :> IDisposable
            }
            let disp = Application.Current.Dispatcher
            Async.StartWithContinuations(
(* ERROR -> *)  disp.InvokeAsync((fun() -> callback.Invoke(context))),
                (fun()->()), 
                error, 
                cancel,
                ct
            )
        )
    }
end

有谁知道为什么会出现这个错误以及解决方案是什么?

【问题讨论】:

    标签: f# async-await


    【解决方案1】:

    错误消息说明了一切:Dispatcher.InvokeAsync 返回 DispatcherOperationAsync.StartWithContinuations 需要 Async

    您可以等待DispatcherOperation.Task

    Async.StartWithContinuations(
        disp.InvokeAsync((fun() -> callback.Invoke(context))).Task |> Async.AwaitTask,
        ignore,
        error,
        cancel,
        ct)
    

    请注意,使用 async 包装表达式不会自动使其异步,并且包装已经异步的流而不等待两次可能甚至根本不执行内部异步:

    let print = async { printfn "Can we observe this?" }
    
    async { return print } |> Async.RunSynchronously // nothing printed
    async { return! print } |> Async.RunSynchronously // prints message
    

    所以这不是异步的:

    Async.StartWithContinuations(
        async { disp.Invoke((fun() -> callback.Invoke(context))) },
        ignore,
        error,
        cancel,
        ct)
    

    这甚至可能不会调用回调(取决于InvokeAsync 的实现,Tasks 通常是隐式启动的):

    Async.StartWithContinuations(
        async { disp.InvokeAsync((fun() -> callback.Invoke(context))) },
        ignore, 
        error, 
        cancel,
        ct)
    

    最重要的是,回调(通常是成功的,这里:ignore)可能会在内部回调返回之前调用

    【讨论】:

    • 这里为什么要使用Async.AwaitIAsyncResult 而不是Async.AwaitTask?后者更清晰(大多数人不知道IAsyncResult 是什么)并且可能也会更有效率。
    • 并且在async 中使用Invoke 根本不会使代码异步。您不妨直接致电disp.Invoke()
    • @svick 谢谢,我“修复”了Async.AwaitTask。第二个示例旨在“使类型匹配”,但我应该正确解释。
    【解决方案2】:

    我已经解决了我的问题。

    方法“StartWithContinuations”的第一个参数“computation”类型为 Async,所以我用 async{} 封闭了第一个参数。

    let disp = Application.Current.Dispatcher                
                Async.StartWithContinuations(
                    async {disp.InvokeAsync((fun() -> callback.Invoke(context)))},
                    ignore, 
                    error, 
                    cancel,
                    ct
                )
            )
    

    【讨论】:

    • 这可能不会做你想做的事......不过是个好主意,激发了我对答案的编辑。
    • 这将有效地忽略InvokeAsync 的结果,因此不会在正确的时间执行延续。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多