Unity:未命名注册的隐式解析参数 [英] Unity: Implicit ResolvedParameter for unnamed registrations

本文介绍了Unity:未命名注册的隐式解析参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

The UserService constructor has two parameters, a IUnitOfWork and a IUserRepository:

public UserService(IUnitOfWork unitofWork, IUserRepository userRepository) 
{ ... }

我正在使用命名注册以区分 IUnitOfWork 的多个实例,因此在注册 UserService 与Unity容器,我需要使用 InjectionConstructor 明确指定参数:

I am using named registrations to differentiate between multiple instances of IUnitOfWork, so when registering the UserService with the Unity container, I need to explicitly specify the parameters using an InjectionConstructor:

container.RegisterType<IUserService, UserService>(
    new InjectionConstructor(
        new ResolvedParameter<IUnitOfWork>("someContext"),
        new ResolvedParameter<IUserRepository>()
    )
);

是否可以 new ResolvedParameter< IUserRepository>() / code>要省略?我希望Unity可以隐含地推导出这个参数,因为不需要一个命名的注册。代码如下所示:

container.RegisterType<IUserService, UserService>(
    new InjectionConstructor(
        new ResolvedParameter<IUnitOfWork>("someContext")
    )
);

如果我不需要使用 InjectionConstructor

推荐答案

根据 InjectionConstructor ,我想出了这个RequiredInjectionConstructor。它允许您指定任何参数集,它将尝试查找一个构造函数,该构造函数必须具有(至少)传递的注入参数集。如果有多个符合此条件的构造函数,则选择参数最少的构造函数。剩下的构造函数参数被假定为未命名的解析参数。

Based on InjectionConstructor, I came up with this RequiredInjectionConstructor. It allows you to specify any set of arguments and it will attempt to find a constructor which is required to have (at a minimum) the passed set of injection parameters. If there are multiple constructors that meet this criteria, it chooses the constructor with the least number of parameters. The remaining constructor parameters are assumed to be unnamed resolved parameters.

我还没有完成一整套单元测试,所以让我知道如果你遇到任何问题。

I haven't performed a full suite of unit tests on it yet, so let me know if you encounter any issues.

/// <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;
    }
}

这篇关于Unity:未命名注册的隐式解析参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆