从工厂继承构造函数参数

Inherit ConstructorParameter from a factory

我正在使用 Ninject 出厂扩展。是否可以使自动创建的 ConstructorArguments 具有 inherit = true?我希望以下内容起作用:

kernel.Bind<IFactory>.ToFactory();

IFactory 在哪里:

public interface IFactory {
    View GetView(object param);
}

并且param被提交给View:s依赖项(View不需要它)。

我知道我可以自己实现工厂,但我想知道工厂扩展是否有开箱即用的(未记录的)支持?

不,开箱即用不支持。 它开箱即用只有两件事:

  • 当参数名称匹配时注入一个参数
  • (当IFactory方法名以Get开头时)

您可以做的是编写您自己的自定义 IInstanceProvider。 请参阅 ,其中描述了如何应用您的自定义 IInstanceProvider

IInstanceProvider 是放置此类(自定义)内容的地方。 我们所做的是编写一个通用实例提供程序,它执行一些反射来检测几个自定义属性,然后将这些属性解释为允许几件事(继承、名称匹配时注入、类型匹配时注入、约束解析、确定将实例化哪种类型、添加请求的参数,...)

但是,对于单个应用程序(不是在一个软件中,而是在使用它的一段代码中),它可能不值得。我会自己实现工厂。

自定义 IInstanceProvider 继承 ConstructorArgument

public class InheritingConstructorArgumentsInstanceProvider : StandardInstanceProvider
{
    protected override IConstructorArgument[] GetConstructorArguments(
        MethodInfo methodInfo,
        object[] arguments)
    {
        return methodInfo
            .GetParameters()
            .Select((parameter, index) =>
                new ConstructorArgument(
                    parameter.Name,
                    arguments[index],
                    true))
            .Cast<IConstructorArgument>()
            .ToArray();
    }
}

然后绑定如下:

kernel
    .Bind<IFactory>()
    .ToFactory(() => new InheritingConstructorArgumentsInstanceProvider());

单元测试证明它有效

完整代码如下:

namespace NinjectTest.CustomFactory
{
    using System.Linq;
    using System.Reflection;
    using FluentAssertions;
    using Ninject;
    using Ninject.Extensions.Factory;
    using Ninject.Parameters;
    using Xunit;

    public class InheritingConstructorArgumentsInstanceProvider : StandardInstanceProvider
    {
        protected override IConstructorArgument[] GetConstructorArguments(
            MethodInfo methodInfo,
            object[] arguments)
        {
            return methodInfo
                .GetParameters()
                .Select((parameter, index) =>
                    new ConstructorArgument(
                        parameter.Name,
                        arguments[index],
                        true))
                .Cast<IConstructorArgument>()
                .ToArray();
        }
    }

    public class Foo
    {
        public Bar Bar { get; private set; }

        public Foo(Bar bar)
        {
            Bar = bar;
        }
    }

    public class Bar
    {
        public string Id { get; private set; }

        public Bar(string id)
        {
            Id = id;
        }
    }

    public interface IFactory
    {
        Foo Create(string id);
    }

    public class Test
    {
        [Fact]
        public void Foo()
        {
            var kernel = new StandardKernel();
            kernel
                .Bind<IFactory>()
                .ToFactory(() => new InheritingConstructorArgumentsInstanceProvider());

            const string expectedId = "Hello You!";

            kernel.Get<IFactory>().Create(expectedId).Bar.Id.Should().Be(expectedId);
        }
    }
}

我实现了自定义提供者,很简单:

public class InheritingConstructorArgumentsInstanceProvider : StandardInstanceProvider
{
    protected override IConstructorArgument[] GetConstructorArguments(
        MethodInfo methodInfo, object[] arguments)
    {
        var parameters = methodInfo.GetParameters();
        var constructorArguments = new IConstructorArgument[parameters.Length];
        for (int i = 0; i < parameters.Length; i++)
        {
            constructorArguments[i] = new ConstructorArgument(
                parameters[i].Name, arguments[i], true);
        }

        return constructorArguments;
    }
}

感谢您指引我正确的方向!