使用在C#中声明的虚拟异步任务并在F#中覆盖它

Jos*_*den 5 .net c# f# asynchronous async-await

目前我有一段用C#编写的代码,它被一段F#代码用作.NET库.这是问题:

假设我在C#库中有以下类:

namespace Jaxrtech.Logic
{
    public class Initializer
    {
        public Initializer()
        {
        }

        public async Task Setup()
        {
            // Run implementation independed setup here

            // Now call the implementation specific override
            await OnSetup();

            // Do any additional setup after the implemntation specific stuff
        }

        // Allow for custom setup tasks to be ran by the Initializer
        protected virtual async Task OnSetup()
        {
            // Return a completed task by default
            await Task.FromResult(0);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在F#中覆盖,如下:

open System.Threading.Tasks
open Jaxrtech.Logic

type CustomInitializer() =
    inherit Initializer()

    ...

    override this.OnSetup(): Task = async {
        // custom async logic here
        // ex:
        do! updateTables()
        do! validateData()
    }

    (* Error: This expression was expected to have type
                Task
              but here has type
                Async<'a>' *)
Run Code Online (Sandbox Code Playgroud)

问题是this.OnSetup()成员正在尝试返回,Async<unit>但C#库期望正常为空Task.我试过查看MSDN Control.Async文档,但没有找到任何有用的.Async.StartAsTask仍然返回一个类型化的任务,即Task<'a>.所以这样的事情似乎无法解决问题:

override this.OnSetup(): Task =
    let f: Async<unit> = async {
        // Implementation specific setup code here
    }
    Async.StartAsTask f
Run Code Online (Sandbox Code Playgroud)

相反,现在您会收到类似的错误消息:

This expression was expected to have type  
  Task  
but here has type  
  Task<'a>'
Run Code Online (Sandbox Code Playgroud)

然后你可以问我为什么不首先使用事件.这样做的主要原因是因为你将要返回,async void所以没有办法正确使用await事件来完成.

最后,幸运的是我可以控制C#和F#库.任何合理的方式来覆盖此protected virtual async Task功能或类似的将非常感激.

des*_*sco 6

鉴于Task<'a>源自Task您可以稍微修改您的最后一个片段

override this.OnSetup(): Task =
    let f: Async<unit> = async {
    // Implementation specific setup code here
    }
    upcast Async.StartAsTask f
Run Code Online (Sandbox Code Playgroud)