原文做者: Thomas Levesque
原文連接:https://thomaslevesque.com/2020/03/18/lazily-resolving-services-to-fix-circular-dependencies-in-net-core/ide
在構建應用程序時,良好的設計應該應避免服務之間的循環依賴, 循環依賴是指某些組件直接或間接相互依賴,好比下面這樣函數
若是您不當心在.NET Core應用程序使用了依賴項注入,而且引入瞭如下循環依賴關係,你要知道的是,項目啓動會報一個循環依賴的錯誤,由於依賴關係週期中涉及的組件的解析將失敗,好比,你具備如下組件:測試
System.InvalidOperationException: A circular dependency was detected for the service of type 'Demo.IA'.ui
因此應該去避免這些設計。this
可是,當實際應用程序達到必定程度的複雜性時,有時可能很難避免,有一天不當心給服務添加了一個依賴項,啓動報錯了,事情忽然浮出水面, 所以,您面臨一個選擇:重構,來解決循環依賴的問題,理想狀況下,應該去選擇重構,可是實際狀況中,可能項目比較緊,可能沒有時間重構代碼,由於要作完整的迴歸測試。翻譯
一種方法是將注入 IServiceProvider 到您的類中,並services.GetRequiredService
class C : IC { private readonly IA _a; public C(IA a) { _a = a; } public void Bar() { ... _a.Foo() ... } }
爲了不依賴性循環,能夠注入 IServiceProvider, 而後這樣重寫它:code
class C : IC { private readonly IServiceProvider _services; public C(IServiceProvider services) { _services = services; } public void Bar() { ... var a = _services.GetRequiredService<IA>(); a.Foo(); ... } }
因爲在構建IA時再也不須要解決問題C,所以中斷了循環(至少在構建過程當中),並解決了問題,可是,我不太喜歡這種方法,由於這樣強制依賴了IOC,若是我使用了 Autofac 等,另外一個問題是我很難看到類的依賴關係,它不明顯。blog
Lazy<T>
下邊的方法我利用了Lazy
public static IServiceCollection AddLazyResolution(this IServiceCollection services) { return services.AddTransient( typeof(Lazy<>), typeof(LazilyResolved<>)); } private class LazilyResolved<T> : Lazy<T> { public LazilyResolved(IServiceProvider serviceProvider) : base(serviceProvider.GetRequiredService<T>) { } }
而後再 Startup.cs 中的 ConfigureServices 方法中這樣寫
services.AddLazyResolution();
在依賴的類中IA,注入Lazy
class C : IC { private readonly Lazy<IA> _a; public C(Lazy<IA> a) { _a = a; } public void Bar() { ... _a.Value.Foo(); ... } }
注意:不要訪問構造函數中的值,保存Lazy
這個解決方案不是完美的,可是它解決了最初的問題卻沒有太多麻煩,而且依賴項仍然在構造函數中明確聲明,我能夠看到類之間的依賴關係。
歡迎掃碼關注咱們的公衆號 【全球技術精選】,專一國外優秀博客的翻譯和開源項目分享,也能夠添加QQ羣 897216102