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

sTo*_*rov 4 architecture dependency-injection 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;
        }

      }
Run Code Online (Sandbox Code Playgroud)

而我的设置:

container.Register<IProductService, ProductService>();
container.Register<IProductRepository>(() => new ProductRepository());
Run Code Online (Sandbox Code Playgroud)

运行代码时,出现以下异常:

For the container to be able to create ProductService, it should contain exactly one public constructor, but it has 0.
Run Code Online (Sandbox Code Playgroud)

我的问题:

1)是否有特定原因导致注入内部类在体系结构/设计方面不起作用?

2)如何实现这种行为(使用不应该公开的类进行依赖注入),并希望得到这种行为?

Ste*_*ven 5

Simple Injector会尝试为您提供明智的默认设置。默认情况下,它仅限于具有单个公共构造函数的自动装配类型,因为具有多个构造函数是一种反模式。默认情况下,Simple Injector仅注入公共构造函数,因为为了使Simple Injector能够安全地调用类型的构造函数,此对象必须是公共的。例如,当应用程序在(部分信任)沙箱中运行时,Simple Injector将无法调用内部构造函数,尽管可以完全信任地调用内部构造函数,但是创建此类类型的速度较慢。为了提高性能,最好使类型和构造函数保持公开状态。

除了这些技术限制之外,在正常情况下,组件及其构造函数也将是公共的,因为您通常总是需要访问该组件的外部使用者。这样的使用者的例子是您的单元测试项目和您的组合根项目

因此,明智的默认设置是“一个公共构造函数”,但是类型本身不必是公共的,尽管解析内部类型会比较慢,并且可能并不总是在沙箱中工作。换句话说,当您不在沙盒中运行时(例如Silverlight或Windows Phone),Simple Injector将能够解析内部类型,只要它们具有单个公共构造函数即可。

但是,如果您确实需要或希望构造函数是内部的,则可以通过实现和注册一个custom来覆盖构造函数解析行为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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

var container = new Container();

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

// Normal registrations here
Run Code Online (Sandbox Code Playgroud)