Unity容器構造函數參數循環引用問題及解決
關鍵字:
Unity .NET5 .NET6 循環引用 循環依賴 Quartz StdSchedulerFactory
起因
在.NET6/.NET5環境中,使用Unity替換默認容器,用到了Quartz任務管理,發現在註冊ISchedulerFactory為StdSchedulerFactory後,獲取ISchedulerFactory會報錯:
System.StackOverflowException:「Exception_WasThrown」
根據報錯推測是產生了循環引用,導致堆棧溢出;
進一步嘗試發現不用Unity用默認容器,沒有這個問題;
直接看解決方法,到文章末尾。
重現
定義測試實體
public class TestModel { public string Code { get; set; } public string Name { get; set; } public TestModel() { } //自身引用; 注意這裡 public TestModel(TestModel model) { this.Code = model.Code; this.Name = model.Name; } }
定義接口及實現
public interface ITest { string Hello(string name); } public class TestImpl : ITest { public TestImpl() { } //用unity容器時,model定義成循環引用了,會報錯 public TestImpl(TestModel model) { } public string Hello(string name) { return $"Hello, {name}"; } }
應用
註冊及獲取ITest
默認容器運行正常
引用unity容器:略
再次運行,報錯
解決
這是個很「奇怪」的問題,接口實現類TestImpl,因為有一個「沒用到」的構造函數,其參數TestModel有一個「沒用到」的構造函數,引用自身;會導致Unity容器獲取該接口時報錯。好繞,看圖。
看「起因」Quartz中的接口實現StdSchedulerFactory,NameValueCollection有引用自身的構造函數。
解決辦法:刪除接口實現中的帶參構造函數或自身引用的構造函數都可以;但在涉及三方dll的時候不方便。
更好的辦法:對自身引用的參數做下註冊。
public void ConfigureServices(IServiceCollection services) { //添加TestModel註冊 services.AddTransient(typeof(TestModel), _ => new TestModel()); //註冊ITest services.AddScoped<ITest, TestImpl>(); }
添加註冊之後,運行正常。