简单的注入器和内部构造器

时间:2014-02-11 08:38:48

标签: architecture dependency-injection simple-injector

我正在开发一个小型库,并使用Simple Injector进行我的DI。 类库有一个访问点(我猜的某种服务),它是public,它有一些internal服务和存储库。

我看到Simple Injector不支持使用内部构造函数的构造函数注入。 例如,我的产品服务如下:

     internal class ProductService : IProductService
      {
        private IProductRepository _productRepository;

        internal ProductService(IProductRepository repository)
        {
          if (repository == null) throw new ArgumentNullException("repository");

          _productRepository = repository;
        }

      }

我的设置:

container.Register<IProductService, ProductService>();
container.Register<IProductRepository>(() => new ProductRepository());

当我运行代码时,我得到以下异常:

For the container to be able to create ProductService, it should contain exactly one public constructor, but it has 0.

我的问题:

1)注入内部类在架构/设计方面是否有效的具体原因是什么?

2)如何实现这种行为(使用不应公开的类的依赖注入)并且是否需要?

1 个答案:

答案 0 :(得分:5)

Simple Injector试图给你一个合理的默认值。默认情况下,由于具有multiple constructors is an anti-pattern,因此仅限于使用单个公共构造函数的自动布线类型。默认的Injector只注入公共构造函数,因为Simple Injector能够安全地调用类型的构造函数,所以它必须是公共的。例如,当应用程序在(部分信任)沙箱中运行时,Simple Injector将无法调用内部构造函数,虽然可以完全信任地调用内部构造函数,但创建此类型的速度较慢。为了提高性能,最好将类型和构造函数保持公开。

除了这些技术限制外,在正常情况下,组件及其构造函数将是公共的,因为您通常总是需要访问该组件的外部使用者。此类消费者的示例是您的单元测试项目和composition root project

因此,合理的默认值是“一个公共构造函数”,但类型本身不必是公共的,尽管解析内部类型会更慢并且可能并不总是在沙箱中工作。换句话说,当您没有在沙箱(例如Silverlight或Windows Phone)中运行时, Simple Injector将能够解析内部类型,只要它们有一个< em> public 构造函数。

但是,如果您确实需要或希望构造函数是内部的,则可以通过实现和注册自定义IConstructorResolutionBehavior来覆盖构造函数解析行为。这是一个例子:

public class InternalConstructorResolutionBehavior : IConstructorResolutionBehavior
{
    private IConstructorResolutionBehavior original;

    public InternalConstructorResolutionBehavior(Container container) {
        this.original = container.Options.ConstructorResolutionBehavior;
    }

    public ConstructorInfo GetConstructor(Type implementationType) {
        if (!implementationType.GetConstructors().Any()) {
            var internalCtors = implementationType.GetConstructors(
                BindingFlags.Instance | BindingFlags.NonPublic)
                .Where(c => !c.IsPrivate)
                .ToArray();

            if (internalCtors.Length == 1) return internalCtors.First();
        }

        return this.original.GetConstructor(implementationType);
    }
}

此自定义构造函数解析行为可以按如下方式注册:

var container = new Container();

container.Options.ConstructorResolutionBehavior = 
    new InternalConstructorResolutionBehavior(container);

// Normal registrations here