繁体   English   中英

当您只能运行同步时满足异步接口方法

[英]Satisfying an async interface method when you can only run sync

我正在使用作为 COM+ 对象实现的“API”(我松散地使用该术语)。 据我所知,不支持 COM+ 提供的任何排队功能,但我对 COM+ 的了解几乎为零。 把它和一粒盐一起吃。 我只有一种方法可用: invoke ,它是同步的。

出于个人的聪明才智,我围绕这个 COM+ 对象创建了一个 Web Api 包装器,它只有一个端点,使用请求的 post 主体调用 COM+ 对象。 这使我可以改为对 Web Api 进行异步调用(以及从我的应用程序中删除可怕的依赖项)。

现在,我正在创建一个库来基本上抽象所有这些混乱,但我决定实现一个提供者模式,您可以选择直接使用 COM+ 或 Web Api 包装器。 很明显,我有一个接口,包含同步和异步方法。 Web Api 提供程序当然没问题,因为您可以通过任何一种方式执行 HTTP 请求,但是我与 COM+ 提供程序遇到了障碍。 由于异步不是那里的选项。

所以,在我看来,我有三个选择:

  1. “实现”带有NotImplementedException的异步接口方法,这违反了接口隔离原则。

  2. 做一些不明智的事情,例如使用Task.Run ,我知道在这种情况下它并不是真正的异步,并且基本上是针对针对我的库进行编程的任何人。

  3. 做一些事情,比如创建接口的同步和异步版本,从接口隔离的角度来看更好,但从提供者模式的角度来看更糟。 如果我依赖于异步接口,那么 COM+ 提供程序将永远无法使用,如果我依赖同步接口,那么我将永远无法使用 Web Api 提供程序的异步方法。

总而言之,我的一般问题是,在需要异步运行某些东西但需要使用的方法只能同步运行的情况下,您会怎么做? 如果没有真正的替代方案,那么满足接口要求的最不冒犯性的方法是什么?

编辑

我忘了再提一个选项:

  1. 在异步实现中调用方法同步,然后简单地返回带有结果的Task.FromResult 这意味着我不会拉新线程(这可能是 Web 应用程序中的一个问题),但我不确定这是否真的比Task.Run更好, Task.Run它实际上是向消费者撒谎“异步”。

我找到的解决方案是使用Task.FromResult返回一个Task即使没有进行任何异步操作。 虽然这实际上不是异步的,但它满足接口。 然后,我对该方法进行了注释,以指出它将运行同步,并且在无法阻止线程(例如 GUI)的情况下,应将其作为委托传递给Task.Run 使用Task.Run并不适用于所有情况(例如 Web 应用程序),它是一个实现细节,应该由库的使用者决定。

也就是说,要真正实现这一点,您需要处理三个Task场景:完成、故障和取消。 这是执行所有这些操作的实际代码:

public Task<int> DoSomethingAsync(CancellationToken cancellationToken)  
{
    if (cancellationToken.IsCancellationRequested)
    {
        return Task.FromCanceled<int>(cancellationToken);
    }

    try
    {
        return Task.FromResult<int>(DoSomething());
    }
    catch (Exception e)
    {
        return Task.FromException<int>(e);
    }
}

首先,这可确保操作未被取消。 如果是,则返回已取消的任务。 然后,我们需要做的同步工作被包裹在一个 try..catch 块中。 如果抛出异常,我们需要返回包含该异常的错误任务。 最后,如果它正确完成,我们返回一个已完成的任务。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM