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>(); }
添加注册之后,运行正常。