我有一個運行了十年的舊版 .NET Framework 應用程式。
有一個界面:
interface IService
{
void Run();
}
并且這個介面在很多現有的類中都實作了。有一個中央管理器負責獲取所有實作的類IService并呼叫Run()每個類的方法。(此代碼已經可用并按預期運行)。
現在,我想再添加一個實作相同的類IService,但我想Run()成為一個async Task而不是一個void,因為我正在處理這個新類中的 API 呼叫。我不想打擾中央管理器如何作業的現有功能。
uj5u.com熱心網友回復:
您不能以保持向后兼容性的方式將介面更改為(可選地)支持異步呼叫——這是一件好事。
解釋
請記住,介面的全部目的是保證所有呼叫者都可以與該介面的具體實作進行互動,而無需了解具體型別本身。將方法實作為async更改該方法的簽名(即,通過回傳 aTask<>并可能期望一個await關鍵字,具體取決于它的呼叫方式),因此會破壞介面。您可以更改簽名,但根據定義,這會破壞與現有介面的向后兼容性。
選項
鑒于此,這個問題有三個教科書式的解決方案:
- 按照@Neil 的回答中的建議,處理現有同步介面中的異步呼叫。這保持了向后兼容性,但消除了異步呼叫的好處。
- 更改要使用的介面
async,因此需要更新所有實作。這是最具侵入性的方法,如果您不擁有所有實作,則可能不實用。 - 按照@Ryan Wilson 的評論中的建議,創建一個新
async版本的介面(例如IServiceAsync),供需要異步功能的實作和呼叫者使用。
如果您的優先級完全是與現有代碼的向后兼容性,而不是異步處理的性能優勢,那么您應該選擇第一個選項。
然而,假設您想要異步呼叫的性能優勢,考慮到您正在使用遺留代碼,最后一個選項最有意義;如果您不擁有所有實作,那將尤其如此。
該答案的其余部分將采用第三種選擇。
基礎介面
如果合適,您的同步和異步介面可以從共享任何非async方法的公共介面派生,從而允許它們在這些場景中互換使用。如果您的代碼不依賴任何隱含的async方法,這將很有用。您的問題并未暗示這一點,但我假設您的界面可能比此處包含的內容更多。
中央經理
您的中央管理器將需要更新以查找IService和IServiceAsync,并有條件地呼叫例如RunAsync()后者。只需確保在這種情況下您真正利用了異步功能(例如,通過將它們添加到任務佇列并在任務完成時處理它們)。否則,您將不會從異步介面中獲得任何性能優勢。
影響
我知道您的目標是避免更新您的中央管理器。但不幸的是,沒有辦法在利用 API 呼叫所需的任何異步處理的同時實作這一點。
uj5u.com熱心網友回復:
只需以非異步方式包裝新的異步功能。
class AsyncService : IService
{
public void Run()
{
myasyncFunction().GetAwaiter().GetResult();
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/456304.html
