依赖注入疑难排查:向类构造函数注入同接口类型数组时出现服务解析失败错误
嘿,这个问题我碰到过好多次,咱们一步步来拆解解决:
错误根源
你用的.NET默认DI容器(从AddTransient、BuildServiceProvider这些API来看是Microsoft.Extensions.DependencyInjection)原生不支持自动将多个同类型服务注入为数组类型。虽然你注册了两个IPersonOrderingStrategy实现,但容器不知道要把它们打包成IPersonOrderingStrategy[]注入到PersonCollection的构造函数里,所以抛出了无法解析该类型的错误。
另外提个小细节:你注册了两次MaximumPersonsOrdering,估计是笔误,应该是一个最大排序、一个最小排序(比如MinimumPersonsOrdering)吧?这个不影响当前错误,但后续逻辑可能会有问题。
两种解决方案
方案1:改用IEnumerable<T>(推荐)
DI容器原生支持将所有注册的T实例注入到IEnumerable<T>参数中,这是最简单的解决方式:
修改PersonCollection的构造函数参数类型,从数组改为IEnumerable<IPersonOrderingStrategy>,如果内部还是需要数组,可以在构造函数里转成数组:
public class PersonCollection : IPersonCollection { private IDictionary<int, IPerson> _persons; private IPerson _maxOrMinPerson; private readonly IPersonOrderingStrategy[] _personOrderingStrategies; private string _propertyName { get; set; } private string _maxMinOrdering { get; set; } // 把参数改成IEnumerable<T> public PersonCollection(IEnumerable<IPersonOrderingStrategy> personOrderingStrategies) { _persons = new Dictionary<int, IPerson>(); // 转成数组存到私有字段里 _personOrderingStrategies = personOrderingStrategies.ToArray(); } }
这个方法不需要修改任何DI注册代码,容器会自动把所有注册的IPersonOrderingStrategy实例注入进来。
方案2:手动注册数组类型(如果一定要用数组参数)
如果你坚持要保留数组类型的构造参数,可以在DI注册时手动告诉容器如何创建这个数组:
public void ConfigureServices() { _serviceColletcion.AddTransient<IPerson, Person>(); _serviceColletcion.AddTransient<IPersonCollection, PersonCollection>(); _serviceColletcion.AddTransient<IPersonOrderingStrategy, MaximumPersonsOrdering>(); // 这里修正笔误,改成你需要的另一个实现 _serviceColletcion.AddTransient<IPersonOrderingStrategy, MinimumPersonsOrdering>(); _serviceColletcion.AddTransient<IPersonFactory, PersonFactory>(); // 手动注册数组类型的工厂 _serviceColletcion.AddTransient<IPersonOrderingStrategy[]>(sp => sp.GetServices<IPersonOrderingStrategy>().ToArray() ); _serviceProvider = _serviceColletcion.BuildServiceProvider(); }
这段代码告诉DI容器:当需要解析IPersonOrderingStrategy[]时,调用sp.GetServices<IPersonOrderingStrategy>()获取所有注册的实例,再转成数组返回。
验证修改
改完之后,再调用Resolve<IPersonCollection>()就应该能正常解析了,容器会正确注入所有的排序策略实例。
内容的提问来源于stack exchange,提问作者ofer gertz

