Dependency injection Unity:未命名注册的隐式ResolvedParameter

Dependency injection Unity:未命名注册的隐式ResolvedParameter,dependency-injection,inversion-of-control,unity-container,ioc-container,onion-architecture,Dependency Injection,Inversion Of Control,Unity Container,Ioc Container,Onion Architecture,UserService构造函数有两个参数,一个是IUnitOfWork,一个是IUserRepository: public UserService(IUnitOfWork unitofWork, IUserRepository userRepository) { ... } 我使用来区分IUnitOfWork的多个实例,因此在向Unity容器注册UserService时,我需要使用InjectionConstructor显式指定参数: container.RegisterType<I

UserService
构造函数有两个参数,一个是
IUnitOfWork
,一个是
IUserRepository

public UserService(IUnitOfWork unitofWork, IUserRepository userRepository) 
{ ... }
我使用来区分
IUnitOfWork
的多个实例,因此在向Unity容器注册
UserService
时,我需要使用
InjectionConstructor
显式指定参数:

container.RegisterType<IUserService, UserService>(
    new InjectionConstructor(
        new ResolvedParameter<IUnitOfWork>("someContext"),
        new ResolvedParameter<IUserRepository>()
    )
);
container.RegisterType(
新注入构造函数(
新的ResolvedParameter(“someContext”),
新的ResolvedParameter()
)
);
是否可以省略
新的ResolvedParameter()
?由于不需要命名注册,我希望Unity隐式推导此参数。
代码如下所示:

container.RegisterType<IUserService, UserService>(
    new InjectionConstructor(
        new ResolvedParameter<IUnitOfWork>("someContext")
    )
);
container.RegisterType(
新注入构造函数(
新的ResolvedParameter(“someContext”)
)
);

如果我不需要使用
InjectionConstructor

的话,就可以这样做了。您愿意用Unity的DependencyAttribute装饰您的构造函数吗?此解决方案是直接的、内置的,允许您选择命名依赖项。但它确实用Unity-goo“弄脏”了你的构造函数

public UserService(
    [Dependency("someContext")]IUnitOfWork unitofWork, 
    IUserRepository userRepository) 
{ ... }
另一个解决方案是编写定制的BuilderStrategy和UnityContainerExtension。这需要做更多的工作。

基于此,我提出了这个RequiredInjection构造函数。它允许您指定任何一组参数,并且它将尝试找到一个构造函数,该构造函数需要(至少)传递一组注入参数。如果有多个构造函数满足此条件,它将选择参数数量最少的构造函数。其余构造函数参数假定为未命名的已解析参数

我还没有对它执行完整的单元测试,所以如果您遇到任何问题,请告诉我

/// <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;
    }
}
//
///保存所需最小值集合的类
///构造函数的参数,以便容器可以
///无法配置为调用此构造函数。
/// 
公共类RequiredInjectionConstructor:InjectionMember
{
私有只读列表_所需参数值;
/// 
///创建该外观的新实例
///对于具有最小给定所需参数集的构造函数。
/// 
///参数的值,这将
///可以转换为对象。
公共RequiredInjectConstructor(参数对象[]requiredParameterValues)
{
_requiredParameterValues=InjectionParameterValue.TopParameters(requiredParameterValues.ToList();
}
/// 
///将策略添加到以配置
///容器使用所需的参数值调用此构造函数。
/// 
///接口已注册,在此实现中被忽略。
///键入以注册。
///用于解析类型对象的名称。
///要向其中添加策略的策略列表。
public override void AddPolicies(类型serviceType、类型implementationType、字符串名称、IPolicyList策略)
{
ConstructorInfo-ctor=FindConstructor(实现类型,_requiredParameterValues);
IEnumerable selectedConstructorParameterValues=GetSelectedConstructorParameterValues(ctor,_requiredParameterValues);
政策。设定(
新指定的构造函数SelectorPolicy(ctor,selectedConstructorParameterValues.ToArray()),
新名称TypeBuildKey(实现类型,名称));
}
私有静态构造函数Info FindConstructor(类型typeToCreate,IEnumerable requiredInjectionParameters)
{
var typeToCreateReflector=新的ReflectionHelper(typeToCreate);
var matchedConstructors=typeToCreateReflector.InstanceConstructors。
其中(ctor=>
{
var constructorParameterTypes=ctor.GetParameters().Select(info=>info.ParameterType);
返回requiredInjectParameters.All(必选=>constructorParameterTypes.Any(必选.MatchesType));
});
if(matchedConstructors.Any())
{
//首选参数数最少的构造函数。
//其他偏好模型可以在这里实现。
返回matchedConstructors.OrderBy(ctor=>
ctor.GetParameters().Count()。
FirstOrDefault();
}
string signature=string.Join(“,”,requiredInjectionParameters.Select(required=>required.ParameterTypeName.ToArray());
抛出新的InvalidOperationException(
Format(“找不到具有最小必需参数的构造函数。类型:{0},必需参数:{1}”),
typeToCreate.FullName,
签署);;
}
私有静态IEnumerable GetSelectedConstructorParameterValues(ConstructorInfo,IEnumerable requiredInjectionParameters)
{
var injectionParameterValues=新列表();
foreach(ctor.GetParameters()中的var参数)
{
var existingInjectionParameter=requiredInjectionParameters.FirstOrDefault(required=>required.MatchesType(parameter.ParameterType));
injectionParameterValues.Add(现有InjectionParameter??新的ResolvedParameter(parameter.ParameterType));
}
返回injectionParameterValue;
}
}

我不希望这样,因为这些服务构成了我们域层的一部分。我不希望他们对统一有任何依赖(或任何基础设施问题)。我很惊讶这是不可能的。从我所读到的和理解的来看,我相信Ninject是可能的。这非常有效。使用这样的反射是否有任何缺点(例如性能)?非常感谢您的帮助。这与标准InjectionConstructor在同一个庄园中使用反射,因此它应该具有大致相同的性能。很高兴我能帮忙!=)