该UserService
构造函数有两个参数,一个是IUnitOfWork
和IUserRepository
:
public UserService(IUnitOfWork unitofWork, IUserRepository userRepository) { ... }
我使用命名注册来区分多个实例IUnitOfWork
,因此在UserService
使用Unity容器注册时,我需要使用以下命令显式指定参数InjectionConstructor
:
container.RegisterType( new InjectionConstructor( new ResolvedParameter ("someContext"), new ResolvedParameter () ) );
有可能new ResolvedParameter
被省略吗?我希望Unity隐式推导出这个参数,因为不需要命名注册. 代码如下所示:
container.RegisterType( new InjectionConstructor( new ResolvedParameter ("someContext") ) );
当我不需要使用时,这将完成InjectionConstructor
.
基于InjectionConstructor,我想出了这个RequiredInjectionConstructor.它允许您指定任何参数集,并且它将尝试查找需要(至少)传递的注入参数集的构造函数.如果有多个构造函数符合此条件,则会选择具有最少参数的构造函数.假设其余构造函数参数是未命名的已解析参数.
我还没有对它进行全套的单元测试,所以如果你遇到任何问题,请告诉我.
/// <summary> /// A class that holds the collection of minimum required /// parameters for a constructor, so that the container can /// be configured to call this constructor. /// </summary> public class RequiredInjectionConstructor : InjectionMember { private readonly List<InjectionParameterValue> _requiredParameterValues; /// <summary> /// Create a new instance of <see cref="RequiredInjectionConstructor"/> that looks /// for a constructor with a minimum of the given required set of parameters. /// </summary> /// <param name="requiredParameterValues">The values for the parameters, that will /// be converted to <see cref="InjectionParameterValue"/> objects.</param> public RequiredInjectionConstructor(params object[] requiredParameterValues) { _requiredParameterValues = InjectionParameterValue.ToParameters(requiredParameterValues).ToList(); } /// <summary> /// Add policies to the <paramref name="policies"/> to configure the /// container to call this constructor with the required parameter values. /// </summary> /// <param name="serviceType">Interface registered, ignored in this implementation.</param> /// <param name="implementationType">Type to register.</param> /// <param name="name">Name used to resolve the type object.</param> /// <param name="policies">Policy list to add policies to.</param> public override void AddPolicies(Type serviceType, Type implementationType, string name, IPolicyList policies) { ConstructorInfo ctor = FindConstructor(implementationType, _requiredParameterValues); IEnumerable<InjectionParameterValue> selectedConstructorParameterValues = GetSelectedConstructorParameterValues(ctor, _requiredParameterValues); policies.Set<IConstructorSelectorPolicy>( new SpecifiedConstructorSelectorPolicy(ctor, selectedConstructorParameterValues.ToArray()), new NamedTypeBuildKey(implementationType, name)); } private static ConstructorInfo FindConstructor(Type typeToCreate, IEnumerable<InjectionParameterValue> requiredInjectionParameters) { var typeToCreateReflector = new ReflectionHelper(typeToCreate); var matchedConstructors = typeToCreateReflector.InstanceConstructors. Where(ctor => { var constructorParameterTypes = ctor.GetParameters().Select(info => info.ParameterType); return requiredInjectionParameters.All(required => constructorParameterTypes.Any(required.MatchesType)); }); if (matchedConstructors.Any()) { // Prefer the constructor that has the least number of arguments. // Other preference models could be implemented here. return matchedConstructors.OrderBy(ctor => ctor.GetParameters().Count()). FirstOrDefault(); } string signature = string.Join(", ", requiredInjectionParameters.Select(required => required.ParameterTypeName).ToArray()); throw new InvalidOperationException( string.Format("Unable to find a constructor with the minimum required parameters. Type: {0}, RequiredParameters: {1}", typeToCreate.FullName, signature)); } private static IEnumerable<InjectionParameterValue> GetSelectedConstructorParameterValues(ConstructorInfo ctor, IEnumerable<InjectionParameterValue> requiredInjectionParameters) { var injectionParameterValues = new List<InjectionParameterValue>(); foreach (var parameter in ctor.GetParameters()) { var existingInjectionParameter = requiredInjectionParameters.FirstOrDefault(required => required.MatchesType(parameter.ParameterType)); injectionParameterValues.Add(existingInjectionParameter ?? new ResolvedParameter(parameter.ParameterType)); } return injectionParameterValues; } }