使用F#实现C#异步接口

3

我需要使用F#实现一个C#接口。这个接口和我需要使用的许多方法都是用C#编写的,并且非常频繁地使用了异步(async)。

C#代码示例需要转换为F#:

public async Task CloseAsync(PartitionContext context, CloseReason reason)
{
    Console.WriteLine(string.Format("Processor Shuting Down.  Partition '{0}', Reason: '{1}'.", this.partitionContext.Lease.PartitionId, reason.ToString()));
    if (reason == CloseReason.Shutdown)
    {
        await context.CheckpointAsync();
    }
}

这可能会有问题,因为F#和C#不使用相同的异步模式或类型。上面的函数是我需要实现的接口的一部分。我的问题在于如何以这样的方式等待context.CheckpointAsync(),使其仍然返回一个Task

这是我试图尝试的方向,但它不起作用。context.CheckpointAsync返回Task<a>而不是Task。另外,其他情况呢?在这些情况下,不需要执行任何操作吗?

interface IEventProcessor with
    member this.CloseAsync(context:PartitionContext, reason:CloseReason) =
        match reason with
        | CloseReason.Shutdown -> context.CheckpointAsync() |> Async.AwaitTask
        | _ -> ()
3个回答

1

Task也是IAsyncResult,这意味着您可以使用Async.AwaitIAsyncResult并忽略输出。

将其全部包装在async计算表达式中,将其作为Task<unit>启动,然后转换为Task。

interface IEventProcessor with

    member __.CloseAsync(context : PartitionContext, reason : CloseReason) = 
        async { 
            if reason = CloseReason.Shutdown then 
                do! context.CheckpointAsync() |> Async.AwaitIAsyncResult |> Async.Ignore
        }
        |> Async.StartAsTask :> Task

0
问题在于,在C#中,它的返回类型是Task而不是Task<T>。在完美的世界里,C#可以有Task<void>
F#3.x内置了从Task<T>Async<T>的绑定,但没有从普通的TaskAsync<T>的绑定。这方面有一些示例,例如How to Async.AwaitTask on plain Task (not Task<T>)? 无论如何,看到您得到的确切错误会很有帮助,但是在这里,您的错误似乎是您正在尝试使用Async.AwaitTask(它将返回Async<T>),但接口必须是Task。因此,您可以完全摆脱Async.AwaitTask()

然后你会得到另一个错误,即匹配的情况不符合,即Shutdown分支返回Task,而另一个分支返回unit。你需要将其更改为也返回Task


这似乎像是作弊...member this.CloseAsync(context:PartitionContext, reason:CloseReason) = match reason with | CloseReason.Shutdown -> context.CheckpointAsync() | _ -> let a = new System.Action(fun t -> ()) new Task(a) - David Crook
在这个问题上,我已经成功地使用OpenAsync,但是在ProcessEventsAsync和CloseAsync方面遇到了问题。魔法连线似乎没有起作用。Open async返回一个任务,但与Close和Process一样没有标记为async前缀。 - David Crook
为什么那是作弊呢?顺便说一下 - 它不会被标记为async修饰符;据我所知,F#不会生成带有该修饰符的方法。而且你在这个方法中也没有执行任何异步代码 - 你只是从一个子方法返回一个任务。没有任何等待或let!的地方。 - Isaac Abraham

0

您可以避免使用async,直接从CheckpointAsync返回任务:

match reason with
| CloseReason.Shutdown -> context.CheckpointAsync() :> Task
| _ -> Task.CompletedTask

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接