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>();
}

添加註冊之後,運行正常。


