在非异步接口中添加异步

Vya*_*Rao 1 .net c# task-parallel-library async-await

我有一个遗留的 .NET Framework 应用程序,\xe2\x80\x99s 已经运行了十年。

\n

有一个界面:

\n
interface IService\n{\n   void Run();\n}\n
Run Code Online (Sandbox Code Playgroud)\n

并且这个接口在很多现有的类中都实现了。有一个中央管理器拾取所有实现类IService并调用Run()每个类上的方法。(此代码已经可用并且按预期运行)。

\n

现在,我想再添加一个实现该功能的类IService,但我希望Run()使用 anasync Task而不是 a void,因为我正在这个新类中处理 API 调用。我不想打扰中央管理器工作方式的现有功能。

\n

Jer*_*ney 7

您无法更改接口以(可选)以保持向后兼容性\xe2\x80\x94 的方式支持异步调用,而\xe2\x80\x99 是一件好事。

\n

解释

\n

请记住,接口的全部目的是保证所有调用者都可以与该接口的具体实现进行交互,而无需了解具体类型本身的任何信息。实现方法作为async更改方法\xe2\x80\x99s 签名\xe2\x80\x94,即,通过返回 aTask<>并可能期望await关键字,具体取决于它\xe2\x80\x99s 的调用方式\xe2\x80\x94 和因此,破坏了接口。您可以更改签名,但根据定义,这会破坏与现有接口的向后兼容性。

\n

选项

\n

鉴于此,这个问题有三种教科书的解决方案:

\n
    \n
  1. 按照@Neil\ 的回答中的建议,处理现有同步接口中的异步调用。这保持了向后兼容性,但消除了异步调用的好处。
  2. \n
  3. 更改要使用的接口async,从而需要更新所有实现。这是最具侵入性的方法,如果您不拥有所有实现,则可能不切实际。
  4. \n
  5. async创建接口的新版本(例如IServiceAsync),供需要异步功能的实现和调用者使用,如@Ryan Wilson\xe2\x80\x99s comment中所建议的。
  6. \n
\n

如果您的首要任务是完全向后兼容现有代码,而不是异步处理的性能优势,那么您应该选择第一个选项。

\n

然而,假设您想要异步调用的性能优势,那么最后一个选项最有意义,因为您正在使用遗留代码;如果您不拥有所有实现,则尤其如此。

\n

本答案的其余部分将假设第三个选项。

\n

基础接口

\n

如果合适,您的同步和异步接口可以派生自共享任何非方法的公共接口async,从而允许它们在这些场景中互换使用。如果您的代码不依赖于任何所涉及的async方法,那么这非常有用。您的问题并不表明这一点,但我假设您的界面可能比此处包含的内容更复杂。

\n

中央经理

\n

您的中央管理器将需要更新以查找 和IServiceIServiceAsync并有条件地调用例如RunAsync()后者。只需确保您\xe2\x80\x99 在这种情况下真正利用异步功能(例如,通过将它们添加到任务队列并在任务完成时处理任务)。否则,您将无法从异步接口中获得任何性能优势。

\n

影响

\n

我知道你的目标是避免更新你的中央经理。但不幸的是,\xe2\x80\x99s 无法在利用 API 调用所需的任何异步处理的同时完成此任务。

\n